Bell 32V release
[unix-history] / usr / src / cmd / f77 / lex.c
CommitLineData
61b0d1e8
TL
1#include "defs"
2#include "tokdefs"
3
4# define BLANK ' '
5# define MYQUOTE (2)
6# define SEOF 0
7
8/* card types */
9
10# define STEOF 1
11# define STINITIAL 2
12# define STCONTINUE 3
13
14/* lex states */
15
16#define NEWSTMT 1
17#define FIRSTTOKEN 2
18#define OTHERTOKEN 3
19#define RETEOS 4
20
21
22LOCAL int stkey;
23LOCAL int stno;
24LOCAL long int nxtstno;
25LOCAL int parlev;
26LOCAL int expcom;
27LOCAL int expeql;
28LOCAL char *nextch;
29LOCAL char *lastch;
30LOCAL char *nextcd = NULL;
31LOCAL char *endcd;
32LOCAL int prevlin;
33LOCAL int thislin;
34LOCAL int code;
35LOCAL int lexstate = NEWSTMT;
36LOCAL char s[1390];
37LOCAL char *send = s+20*66;
38LOCAL int nincl = 0;
39
40struct inclfile
41 {
42 struct inclfile *inclnext;
43 FILEP inclfp;
44 char *inclname;
45 int incllno;
46 char *incllinp;
47 int incllen;
48 int inclcode;
49 ftnint inclstno;
50 } ;
51
52LOCAL struct inclfile *inclp = NULL;
53LOCAL struct keylist { char *keyname; int keyval; } ;
54LOCAL struct punctlist { char punchar; int punval; };
55LOCAL struct fmtlist { char fmtchar; int fmtval; };
56LOCAL struct dotlist { char *dotname; int dotval; };
57LOCAL struct keylist *keystart[26], *keyend[26];
58
59
60
61
62inilex(name)
63char *name;
64{
65nincl = 0;
66inclp = NULL;
67doinclude(name);
68lexstate = NEWSTMT;
69return(NO);
70}
71
72
73
74/* throw away the rest of the current line */
75flline()
76{
77lexstate = RETEOS;
78}
79
80
81
82char *lexline(n)
83ftnint *n;
84{
85*n = (lastch - nextch) + 1;
86return(nextch);
87}
88
89
90
91
92
93doinclude(name)
94char *name;
95{
96FILEP fp;
97struct inclfile *t;
98
99if(inclp)
100 {
101 inclp->incllno = thislin;
102 inclp->inclcode = code;
103 inclp->inclstno = nxtstno;
104 if(nextcd)
105 inclp->incllinp = copyn(inclp->incllen = endcd-nextcd , nextcd);
106 else
107 inclp->incllinp = 0;
108 }
109nextcd = NULL;
110
111if(++nincl >= MAXINCLUDE)
112 fatal("includes nested too deep");
113if(name[0] == '\0')
114 fp = stdin;
115else
116 fp = fopen(name, "r");
117if( fp )
118 {
119 t = inclp;
120 inclp = ALLOC(inclfile);
121 inclp->inclnext = t;
122 prevlin = thislin = 0;
123 infname = inclp->inclname = name;
124 infile = inclp->inclfp = fp;
125 }
126else
127 {
128 fprintf(diagfile, "Cannot open file %s", name);
129 done(1);
130 }
131}
132
133
134
135
136LOCAL popinclude()
137{
138struct inclfile *t;
139register char *p;
140register int k;
141
142if(infile != stdin)
143 clf(&infile);
144free(infname);
145
146--nincl;
147t = inclp->inclnext;
148free(inclp);
149inclp = t;
150if(inclp == NULL)
151 return(NO);
152
153infile = inclp->inclfp;
154infname = inclp->inclname;
155prevlin = thislin = inclp->incllno;
156code = inclp->inclcode;
157stno = nxtstno = inclp->inclstno;
158if(inclp->incllinp)
159 {
160 endcd = nextcd = s;
161 k = inclp->incllen;
162 p = inclp->incllinp;
163 while(--k >= 0)
164 *endcd++ = *p++;
165 free(inclp->incllinp);
166 }
167else
168 nextcd = NULL;
169return(YES);
170}
171
172
173
174
175yylex()
176{
177static int tokno;
178
179 switch(lexstate)
180 {
181case NEWSTMT : /* need a new statement */
182 if(getcds() == STEOF)
183 return(SEOF);
184 crunch();
185 tokno = 0;
186 lexstate = FIRSTTOKEN;
187 yylval = stno;
188 stno = nxtstno;
189 toklen = 0;
190 return(SLABEL);
191
192first:
193case FIRSTTOKEN : /* first step on a statement */
194 analyz();
195 lexstate = OTHERTOKEN;
196 tokno = 1;
197 return(stkey);
198
199case OTHERTOKEN : /* return next token */
200 if(nextch > lastch)
201 goto reteos;
202 ++tokno;
203 if((stkey==SLOGIF || stkey==SELSEIF) && parlev==0 && tokno>3) goto first;
204 if(stkey==SASSIGN && tokno==3 && nextch<lastch &&
205 nextch[0]=='t' && nextch[1]=='o')
206 {
207 nextch+=2;
208 return(STO);
209 }
210 return(gettok());
211
212reteos:
213case RETEOS:
214 lexstate = NEWSTMT;
215 return(SEOS);
216 }
217fatal1("impossible lexstate %d", lexstate);
218/* NOTREACHED */
219}
220\f
221LOCAL getcds()
222{
223register char *p, *q;
224
225top:
226 if(nextcd == NULL)
227 {
228 code = getcd( nextcd = s );
229 stno = nxtstno;
230 prevlin = thislin;
231 }
232 if(code == STEOF)
233 if( popinclude() )
234 goto top;
235 else
236 return(STEOF);
237
238 if(code == STCONTINUE)
239 {
240 lineno = thislin;
241 err("illegal continuation card ignored");
242 nextcd = NULL;
243 goto top;
244 }
245
246 if(nextcd > s)
247 {
248 q = nextcd;
249 p = s;
250 while(q < endcd)
251 *p++ = *q++;
252 endcd = p;
253 }
254 for(nextcd = endcd ;
255 nextcd+66<=send && (code = getcd(nextcd))==STCONTINUE ;
256 nextcd = endcd )
257 ;
258 nextch = s;
259 lastch = nextcd - 1;
260 if(nextcd >= send)
261 nextcd = NULL;
262 lineno = prevlin;
263 prevlin = thislin;
264 return(STINITIAL);
265}
266\f
267LOCAL getcd(b)
268register char *b;
269{
270register int c;
271register char *p, *bend;
272int speclin;
273static char a[6];
274static char *aend = a+6;
275
276top:
277 endcd = b;
278 bend = b+66;
279 speclin = NO;
280
281 if( (c = getc(infile)) == '&')
282 {
283 a[0] = BLANK;
284 a[5] = 'x';
285 speclin = YES;
286 bend = send;
287 }
288 else if(c=='c' || c=='C' || c=='*')
289 {
290 while( (c = getc(infile)) != '\n')
291 if(c == EOF)
292 return(STEOF);
293 ++thislin;
294 goto top;
295 }
296
297 else if(c != EOF)
298 {
299 /* a tab in columns 1-6 skips to column 7 */
300 ungetc(c, infile);
301 for(p=a; p<aend && (c=getc(infile)) != '\n' && c!=EOF; )
302 if(c == '\t')
303 {
304 while(p < aend)
305 *p++ = BLANK;
306 speclin = YES;
307 bend = send;
308 }
309 else
310 *p++ = c;
311 }
312 if(c == EOF)
313 return(STEOF);
314 if(c == '\n')
315 {
316 while(p < aend)
317 *p++ = BLANK;
318 if( ! speclin )
319 while(endcd < bend)
320 *endcd++ = BLANK;
321 }
322 else { /* read body of line */
323 while( endcd<bend && (c=getc(infile)) != '\n' && c!=EOF )
324 *endcd++ = (c == '\t' ? BLANK : c);
325 if(c == EOF)
326 return(STEOF);
327 if(c != '\n')
328 {
329 while( (c=getc(infile)) != '\n')
330 if(c == EOF)
331 return(STEOF);
332 }
333
334 if( ! speclin )
335 while(endcd < bend)
336 *endcd++ = BLANK;
337 }
338 ++thislin;
339 if(a[5]!=BLANK && a[5]!='0')
340 return(STCONTINUE);
341 for(p=a; p<aend; ++p)
342 if(*p != BLANK) goto initline;
343 for(p = b ; p<endcd ; ++p)
344 if(*p != BLANK) goto initline;
345 goto top;
346
347initline:
348 nxtstno = 0;
349 for(p = a ; p<a+5 ; ++p)
350 if(*p != BLANK)
351 if(isdigit(*p))
352 nxtstno = 10*nxtstno + (*p - '0');
353 else {
354 lineno = thislin;
355 err("nondigit in statement number field");
356 nxtstno = 0;
357 break;
358 }
359 return(STINITIAL);
360}
361\f
362LOCAL crunch()
363{
364register char *i, *j, *j0, *j1, *prvstr;
365int ten, nh, quote;
366
367/* i is the next input character to be looked at
368j is the next output character */
369parlev = 0;
370expcom = 0; /* exposed ','s */
371expeql = 0; /* exposed equal signs */
372j = s;
373prvstr = s;
374for(i=s ; i<=lastch ; ++i)
375 {
376 if(*i == BLANK) continue;
377 if(*i=='\'' || *i=='"')
378 {
379 quote = *i;
380 *j = MYQUOTE; /* special marker */
381 for(;;)
382 {
383 if(++i > lastch)
384 {
385 err("unbalanced quotes; closing quote supplied");
386 break;
387 }
388 if(*i == quote)
389 if(i<lastch && i[1]==quote) ++i;
390 else break;
391 else if(*i=='\\' && i<lastch)
392 switch(*++i)
393 {
394 case 't':
395 *i = '\t'; break;
396 case 'b':
397 *i = '\b'; break;
398 case 'n':
399 *i = '\n'; break;
400 case 'f':
401 *i = '\f'; break;
402 case '0':
403 *i = '\0'; break;
404 default:
405 break;
406 }
407 *++j = *i;
408 }
409 j[1] = MYQUOTE;
410 j += 2;
411 prvstr = j;
412 }
413 else if( (*i=='h' || *i=='H') && j>prvstr) /* test for Hollerith strings */
414 {
415 if( ! isdigit(j[-1])) goto copychar;
416 nh = j[-1] - '0';
417 ten = 10;
418 j1 = prvstr - 1;
419 if (j1<j-5) j1=j-5;
420 for(j0=j-2 ; j0>j1; -- j0)
421 {
422 if( ! isdigit(*j0 ) ) break;
423 nh += ten * (*j0-'0');
424 ten*=10;
425 }
426 if(j0 <= j1) goto copychar;
427/* a hollerith must be preceded by a punctuation mark.
428 '*' is possible only as repetition factor in a data statement
429 not, in particular, in character*2h
430*/
431
432 if( !(*j0=='*'&&s[0]=='d') && *j0!='/' && *j0!='(' &&
433 *j0!=',' && *j0!='=' && *j0!='.')
434 goto copychar;
435 if(i+nh > lastch)
436 {
437 err1("%dH too big", nh);
438 nh = lastch - i;
439 }
440 j0[1] = MYQUOTE; /* special marker */
441 j = j0 + 1;
442 while(nh-- > 0)
443 {
444 if(*++i == '\\')
445 switch(*++i)
446 {
447 case 't':
448 *i = '\t'; break;
449 case 'b':
450 *i = '\b'; break;
451 case 'n':
452 *i = '\n'; break;
453 case 'f':
454 *i = '\f'; break;
455 case '0':
456 *i = '\0'; break;
457 default:
458 break;
459 }
460 *++j = *i;
461 }
462 j[1] = MYQUOTE;
463 j+=2;
464 prvstr = j;
465 }
466 else {
467 if(*i == '(') ++parlev;
468 else if(*i == ')') --parlev;
469 else if(parlev == 0)
470 if(*i == '=') expeql = 1;
471 else if(*i == ',') expcom = 1;
472copychar: /*not a string of BLANK -- copy, shifting case if necessary */
473 if(shiftcase && isupper(*i))
474 *j++ = tolower(*i);
475 else *j++ = *i;
476 }
477 }
478lastch = j - 1;
479nextch = s;
480}
481\f
482LOCAL analyz()
483{
484register char *i;
485
486 if(parlev != 0)
487 {
488 err("unbalanced parentheses, statement skipped");
489 stkey = SUNKNOWN;
490 return;
491 }
492 if(nextch+2<=lastch && nextch[0]=='i' && nextch[1]=='f' && nextch[2]=='(')
493 {
494/* assignment or if statement -- look at character after balancing paren */
495 parlev = 1;
496 for(i=nextch+3 ; i<=lastch; ++i)
497 if(*i == (MYQUOTE))
498 {
499 while(*++i != MYQUOTE)
500 ;
501 }
502 else if(*i == '(')
503 ++parlev;
504 else if(*i == ')')
505 {
506 if(--parlev == 0)
507 break;
508 }
509 if(i >= lastch)
510 stkey = SLOGIF;
511 else if(i[1] == '=')
512 stkey = SLET;
513 else if( isdigit(i[1]) )
514 stkey = SARITHIF;
515 else stkey = SLOGIF;
516 if(stkey != SLET)
517 nextch += 2;
518 }
519 else if(expeql) /* may be an assignment */
520 {
521 if(expcom && nextch<lastch &&
522 nextch[0]=='d' && nextch[1]=='o')
523 {
524 stkey = SDO;
525 nextch += 2;
526 }
527 else stkey = SLET;
528 }
529/* otherwise search for keyword */
530 else {
531 stkey = getkwd();
532 if(stkey==SGOTO && lastch>=nextch)
533 if(nextch[0]=='(')
534 stkey = SCOMPGOTO;
535 else if(isalpha(nextch[0]))
536 stkey = SASGOTO;
537 }
538 parlev = 0;
539}
540
541
542
543LOCAL getkwd()
544{
545register char *i, *j;
546register struct keylist *pk, *pend;
547int k;
548
549if(! isalpha(nextch[0]) )
550 return(SUNKNOWN);
551k = nextch[0] - 'a';
552if(pk = keystart[k])
553 for(pend = keyend[k] ; pk<=pend ; ++pk )
554 {
555 i = pk->keyname;
556 j = nextch;
557 while(*++i==*++j && *i!='\0')
558 ;
559 if(*i == '\0')
560 {
561 nextch = j;
562 return(pk->keyval);
563 }
564 }
565return(SUNKNOWN);
566}
567
568
569
570initkey()
571{
572extern struct keylist keys[];
573register struct keylist *p;
574register int i,j;
575
576for(i = 0 ; i<26 ; ++i)
577 keystart[i] = NULL;
578
579for(p = keys ; p->keyname ; ++p)
580 {
581 j = p->keyname[0] - 'a';
582 if(keystart[j] == NULL)
583 keystart[j] = p;
584 keyend[j] = p;
585 }
586}
587\f
588LOCAL gettok()
589{
590int havdot, havexp, havdbl;
591int radix;
592extern struct punctlist puncts[];
593struct punctlist *pp;
594extern struct fmtlist fmts[];
595extern struct dotlist dots[];
596struct dotlist *pd;
597
598char *i, *j, *n1, *p;
599
600 if(*nextch == (MYQUOTE))
601 {
602 ++nextch;
603 p = token;
604 while(*nextch != MYQUOTE)
605 *p++ = *nextch++;
606 ++nextch;
607 toklen = p - token;
608 *p = '\0';
609 return (SHOLLERITH);
610 }
611/*
612 if(stkey == SFORMAT)
613 {
614 for(pf = fmts; pf->fmtchar; ++pf)
615 {
616 if(*nextch == pf->fmtchar)
617 {
618 ++nextch;
619 if(pf->fmtval == SLPAR)
620 ++parlev;
621 else if(pf->fmtval == SRPAR)
622 --parlev;
623 return(pf->fmtval);
624 }
625 }
626 if( isdigit(*nextch) )
627 {
628 p = token;
629 *p++ = *nextch++;
630 while(nextch<=lastch && isdigit(*nextch) )
631 *p++ = *nextch++;
632 toklen = p - token;
633 *p = '\0';
634 if(nextch<=lastch && *nextch=='p')
635 {
636 ++nextch;
637 return(SSCALE);
638 }
639 else return(SICON);
640 }
641 if( isalpha(*nextch) )
642 {
643 p = token;
644 *p++ = *nextch++;
645 while(nextch<=lastch &&
646 (*nextch=='.' || isdigit(*nextch) || isalpha(*nextch) ))
647 *p++ = *nextch++;
648 toklen = p - token;
649 *p = '\0';
650 return(SFIELD);
651 }
652 goto badchar;
653 }
654/* Not a format statement */
655
656if(needkwd)
657 {
658 needkwd = 0;
659 return( getkwd() );
660 }
661
662 for(pp=puncts; pp->punchar; ++pp)
663 if(*nextch == pp->punchar)
664 {
665 if( (*nextch=='*' || *nextch=='/') &&
666 nextch<lastch && nextch[1]==nextch[0])
667 {
668 if(*nextch == '*')
669 yylval = SPOWER;
670 else yylval = SCONCAT;
671 nextch+=2;
672 }
673 else {yylval=pp->punval;
674 if(yylval==SLPAR)
675 ++parlev;
676 else if(yylval==SRPAR)
677 --parlev;
678 ++nextch;
679 }
680 return(yylval);
681 }
682 if(*nextch == '.')
683 if(nextch >= lastch) goto badchar;
684 else if(isdigit(nextch[1])) goto numconst;
685 else {
686 for(pd=dots ; (j=pd->dotname) ; ++pd)
687 {
688 for(i=nextch+1 ; i<=lastch ; ++i)
689 if(*i != *j) break;
690 else if(*i != '.') ++j;
691 else {
692 nextch = i+1;
693 return(pd->dotval);
694 }
695 }
696 goto badchar;
697 }
698 if( isalpha(*nextch) )
699 {
700 p = token;
701 *p++ = *nextch++;
702 while(nextch<=lastch)
703 if( isalpha(*nextch) || isdigit(*nextch) )
704 *p++ = *nextch++;
705 else break;
706 toklen = p - token;
707 *p = '\0';
708 if(inioctl && nextch<=lastch && *nextch=='=')
709 {
710 ++nextch;
711 return(SNAMEEQ);
712 }
713 if(toklen>=8 && eqn(8, token, "function") &&
714 nextch<lastch && *nextch=='(')
715 {
716 nextch -= (toklen - 8);
717 return(SFUNCTION);
718 }
719 if(toklen > VL)
720 {
721 err2("name %s too long, truncated to %d", token, VL);
722 toklen = VL;
723 token[6] = '\0';
724 }
725 if(toklen==1 && *nextch==MYQUOTE)
726 {
727 switch(token[0])
728 {
729 case 'z': case 'Z':
730 case 'x': case 'X':
731 radix = 16; break;
732 case 'o': case 'O':
733 radix = 8; break;
734 case 'b': case 'B':
735 radix = 2; break;
736 default:
737 err("bad bit identifier");
738 return(SNAME);
739 }
740 ++nextch;
741 for(p = token ; *nextch!=MYQUOTE ; )
742 if( hextoi(*p++ = *nextch++) >= radix)
743 {
744 err("invalid binary character");
745 break;
746 }
747 ++nextch;
748 toklen = p - token;
749 return( radix==16 ? SHEXCON : (radix==8 ? SOCTCON : SBITCON) );
750 }
751 return(SNAME);
752 }
753 if( ! isdigit(*nextch) ) goto badchar;
754numconst:
755 havdot = NO;
756 havexp = NO;
757 havdbl = NO;
758 for(n1 = nextch ; nextch<=lastch ; ++nextch)
759 {
760 if(*nextch == '.')
761 if(havdot) break;
762 else if(nextch+2<=lastch && isalpha(nextch[1])
763 && isalpha(nextch[2]))
764 break;
765 else havdot = YES;
766 else if(*nextch=='d' || *nextch=='e')
767 {
768 p = nextch;
769 havexp = YES;
770 if(*nextch == 'd')
771 havdbl = YES;
772 if(nextch<lastch)
773 if(nextch[1]=='+' || nextch[1]=='-')
774 ++nextch;
775 if( ! isdigit(*++nextch) )
776 {
777 nextch = p;
778 havdbl = havexp = NO;
779 break;
780 }
781 for(++nextch ;
782 nextch<=lastch && isdigit(*nextch);
783 ++nextch);
784 break;
785 }
786 else if( ! isdigit(*nextch) )
787 break;
788 }
789 p = token;
790 i = n1;
791 while(i < nextch)
792 *p++ = *i++;
793 toklen = p - token;
794 *p = '\0';
795 if(havdbl) return(SDCON);
796 if(havdot || havexp) return(SRCON);
797 return(SICON);
798badchar:
799 s[0] = *nextch++;
800 return(SUNKNOWN);
801}
802\f
803/* KEYWORD AND SPECIAL CHARACTER TABLES
804*/
805
806struct punctlist puncts[ ] =
807 {
808 '(', SLPAR,
809 ')', SRPAR,
810 '=', SEQUALS,
811 ',', SCOMMA,
812 '+', SPLUS,
813 '-', SMINUS,
814 '*', SSTAR,
815 '/', SSLASH,
816 '$', SCURRENCY,
817 ':', SCOLON,
818 0, 0 } ;
819
820/*
821LOCAL struct fmtlist fmts[ ] =
822 {
823 '(', SLPAR,
824 ')', SRPAR,
825 '/', SSLASH,
826 ',', SCOMMA,
827 '-', SMINUS,
828 ':', SCOLON,
829 0, 0 } ;
830*/
831
832LOCAL struct dotlist dots[ ] =
833 {
834 "and.", SAND,
835 "or.", SOR,
836 "not.", SNOT,
837 "true.", STRUE,
838 "false.", SFALSE,
839 "eq.", SEQ,
840 "ne.", SNE,
841 "lt.", SLT,
842 "le.", SLE,
843 "gt.", SGT,
844 "ge.", SGE,
845 "neqv.", SNEQV,
846 "eqv.", SEQV,
847 0, 0 } ;
848
849LOCAL struct keylist keys[ ] =
850 {
851 "assign", SASSIGN,
852 "automatic", SAUTOMATIC,
853 "backspace", SBACKSPACE,
854 "blockdata", SBLOCK,
855 "call", SCALL,
856 "character", SCHARACTER,
857 "close", SCLOSE,
858 "common", SCOMMON,
859 "complex", SCOMPLEX,
860 "continue", SCONTINUE,
861 "data", SDATA,
862 "dimension", SDIMENSION,
863 "doubleprecision", SDOUBLE,
864 "doublecomplex", SDCOMPLEX,
865 "elseif", SELSEIF,
866 "else", SELSE,
867 "endfile", SENDFILE,
868 "endif", SENDIF,
869 "end", SEND,
870 "entry", SENTRY,
871 "equivalence", SEQUIV,
872 "external", SEXTERNAL,
873 "format", SFORMAT,
874 "function", SFUNCTION,
875 "goto", SGOTO,
876 "implicit", SIMPLICIT,
877 "include", SINCLUDE,
878 "inquire", SINQUIRE,
879 "intrinsic", SINTRINSIC,
880 "integer", SINTEGER,
881 "logical", SLOGICAL,
882 "open", SOPEN,
883 "parameter", SPARAM,
884 "pause", SPAUSE,
885 "print", SPRINT,
886 "program", SPROGRAM,
887 "punch", SPUNCH,
888 "read", SREAD,
889 "real", SREAL,
890 "return", SRETURN,
891 "rewind", SREWIND,
892 "save", SSAVE,
893 "static", SSTATIC,
894 "stop", SSTOP,
895 "subroutine", SSUBROUTINE,
896 "then", STHEN,
897 "undefined", SUNDEFINED,
898 "write", SWRITE,
899 0, 0 };