This commit was generated by cvs2svn to track changes on a CVS vendor
[unix-history] / usr.bin / f2c / lex.c
CommitLineData
f1525c23
WH
1/****************************************************************
2Copyright 1990, 1992, 1993 by AT&T Bell Laboratories and Bellcore.
3
4Permission to use, copy, modify, and distribute this software
5and its documentation for any purpose and without fee is hereby
6granted, provided that the above copyright notice appear in all
7copies and that both that the copyright notice and this
8permission notice and warranty disclaimer appear in supporting
9documentation, and that the names of AT&T Bell Laboratories or
10Bellcore or any of their entities not be used in advertising or
11publicity pertaining to distribution of the software without
12specific, written prior permission.
13
14AT&T and Bellcore disclaim all warranties with regard to this
15software, including all implied warranties of merchantability
16and fitness. In no event shall AT&T or Bellcore be liable for
17any special, indirect or consequential damages or any damages
18whatsoever resulting from loss of use, data or profits, whether
19in an action of contract, negligence or other tortious action,
20arising out of or in connection with the use or performance of
21this software.
22****************************************************************/
23
24#include "defs.h"
25#include "tokdefs.h"
26#include "p1defs.h"
27
28#ifdef NO_EOF_CHAR_CHECK
29#undef EOF_CHAR
30#else
31#ifndef EOF_CHAR
32#define EOF_CHAR 26 /* ASCII control-Z */
33#endif
34#endif
35
36#define BLANK ' '
37#define MYQUOTE (2)
38#define SEOF 0
39
40/* card types */
41
42#define STEOF 1
43#define STINITIAL 2
44#define STCONTINUE 3
45
46/* lex states */
47
48#define NEWSTMT 1
49#define FIRSTTOKEN 2
50#define OTHERTOKEN 3
51#define RETEOS 4
52
53
54LOCAL int stkey; /* Type of the current statement (DO, END, IF, etc) */
55extern char token[]; /* holds the actual token text */
56static int needwkey;
57ftnint yystno;
58flag intonly;
59extern int new_dcl;
60LOCAL long int stno;
61LOCAL long int nxtstno; /* Statement label */
62LOCAL int parlev; /* Parentheses level */
63LOCAL int parseen;
64LOCAL int expcom;
65LOCAL int expeql;
66LOCAL char *nextch;
67LOCAL char *lastch;
68LOCAL char *nextcd = NULL;
69LOCAL char *endcd;
70LOCAL long prevlin;
71LOCAL long thislin;
72LOCAL int code; /* Card type; INITIAL, CONTINUE or EOF */
73LOCAL int lexstate = NEWSTMT;
74LOCAL char *sbuf; /* Main buffer for Fortran source input. */
75LOCAL char *send; /* Was = sbuf+20*66 with sbuf[1390]. */
76LOCAL int maxcont;
77LOCAL int nincl = 0; /* Current number of include files */
78LOCAL long firstline;
79LOCAL char *laststb, *stb0;
80extern int addftnsrc;
81static char **linestart;
82LOCAL int ncont;
83LOCAL char comstart[Table_size];
84#define USC (unsigned char *)
85
86static char anum_buf[Table_size];
87#define isalnum_(x) anum_buf[x]
88#define isalpha_(x) (anum_buf[x] == 1)
89
90#define COMMENT_BUF_STORE 4088
91
92typedef struct comment_buf {
93 struct comment_buf *next;
94 char *last;
95 char buf[COMMENT_BUF_STORE];
96 } comment_buf;
97static comment_buf *cbfirst, *cbcur;
98static char *cbinit, *cbnext, *cblast;
99static void flush_comments();
100extern flag use_bs;
101
102
103/* Comment buffering data
104
105 Comments are kept in a list until the statement before them has
106 been parsed. This list is implemented with the above comment_buf
107 structure and the pointers cbnext and cblast.
108
109 The comments are stored with terminating NULL, and no other
110 intervening space. The last few bytes of each block are likely to
111 remain unused.
112*/
113
114/* struct Inclfile holds the state information for each include file */
115struct Inclfile
116{
117 struct Inclfile *inclnext;
118 FILEP inclfp;
119 char *inclname;
120 int incllno;
121 char *incllinp;
122 int incllen;
123 int inclcode;
124 ftnint inclstno;
125};
126
127LOCAL struct Inclfile *inclp = NULL;
128struct Keylist {
129 char *keyname;
130 int keyval;
131 char notinf66;
132};
133struct Punctlist {
134 char punchar;
135 int punval;
136};
137struct Fmtlist {
138 char fmtchar;
139 int fmtval;
140};
141struct Dotlist {
142 char *dotname;
143 int dotval;
144 };
145LOCAL struct Keylist *keystart[26], *keyend[26];
146
147/* KEYWORD AND SPECIAL CHARACTER TABLES
148*/
149
150static struct Punctlist puncts[ ] =
151{
152 '(', SLPAR,
153 ')', SRPAR,
154 '=', SEQUALS,
155 ',', SCOMMA,
156 '+', SPLUS,
157 '-', SMINUS,
158 '*', SSTAR,
159 '/', SSLASH,
160 '$', SCURRENCY,
161 ':', SCOLON,
162 '<', SLT,
163 '>', SGT,
164 0, 0 };
165
166LOCAL struct Dotlist dots[ ] =
167{
168 "and.", SAND,
169 "or.", SOR,
170 "not.", SNOT,
171 "true.", STRUE,
172 "false.", SFALSE,
173 "eq.", SEQ,
174 "ne.", SNE,
175 "lt.", SLT,
176 "le.", SLE,
177 "gt.", SGT,
178 "ge.", SGE,
179 "neqv.", SNEQV,
180 "eqv.", SEQV,
181 0, 0 };
182
183LOCAL struct Keylist keys[ ] =
184{
185 { "assign", SASSIGN },
186 { "automatic", SAUTOMATIC, YES },
187 { "backspace", SBACKSPACE },
188 { "blockdata", SBLOCK },
189 { "call", SCALL },
190 { "character", SCHARACTER, YES },
191 { "close", SCLOSE, YES },
192 { "common", SCOMMON },
193 { "complex", SCOMPLEX },
194 { "continue", SCONTINUE },
195 { "data", SDATA },
196 { "dimension", SDIMENSION },
197 { "doubleprecision", SDOUBLE },
198 { "doublecomplex", SDCOMPLEX, YES },
199 { "elseif", SELSEIF, YES },
200 { "else", SELSE, YES },
201 { "endfile", SENDFILE },
202 { "endif", SENDIF, YES },
203 { "enddo", SENDDO, YES },
204 { "end", SEND },
205 { "entry", SENTRY, YES },
206 { "equivalence", SEQUIV },
207 { "external", SEXTERNAL },
208 { "format", SFORMAT },
209 { "function", SFUNCTION },
210 { "goto", SGOTO },
211 { "implicit", SIMPLICIT, YES },
212 { "include", SINCLUDE, YES },
213 { "inquire", SINQUIRE, YES },
214 { "intrinsic", SINTRINSIC, YES },
215 { "integer", SINTEGER },
216 { "logical", SLOGICAL },
217 { "namelist", SNAMELIST, YES },
218 { "none", SUNDEFINED, YES },
219 { "open", SOPEN, YES },
220 { "parameter", SPARAM, YES },
221 { "pause", SPAUSE },
222 { "print", SPRINT },
223 { "program", SPROGRAM, YES },
224 { "punch", SPUNCH, YES },
225 { "read", SREAD },
226 { "real", SREAL },
227 { "return", SRETURN },
228 { "rewind", SREWIND },
229 { "save", SSAVE, YES },
230 { "static", SSTATIC, YES },
231 { "stop", SSTOP },
232 { "subroutine", SSUBROUTINE },
233 { "then", STHEN, YES },
234 { "undefined", SUNDEFINED, YES },
235 { "while", SWHILE, YES },
236 { "write", SWRITE },
237 { 0, 0 }
238};
239
240LOCAL void analyz(), crunch(), store_comment();
241LOCAL int getcd(), getcds(), getkwd(), gettok();
242LOCAL char *stbuf[3];
243
244inilex(name)
245char *name;
246{
247 stbuf[0] = Alloc(3*P1_STMTBUFSIZE);
248 stbuf[1] = stbuf[0] + P1_STMTBUFSIZE;
249 stbuf[2] = stbuf[1] + P1_STMTBUFSIZE;
250 nincl = 0;
251 inclp = NULL;
252 doinclude(name);
253 lexstate = NEWSTMT;
254 return(NO);
255}
256
257
258
259/* throw away the rest of the current line */
260flline()
261{
262 lexstate = RETEOS;
263}
264
265
266
267char *lexline(n)
268int *n;
269{
270 *n = (lastch - nextch) + 1;
271 return(nextch);
272}
273
274
275
276
277
278doinclude(name)
279char *name;
280{
281 FILEP fp;
282 struct Inclfile *t;
283 char *lastslash, *s, *s0, *temp;
284 int k;
285
286 if(inclp)
287 {
288 inclp->incllno = thislin;
289 inclp->inclcode = code;
290 inclp->inclstno = nxtstno;
291 if(nextcd)
292 inclp->incllinp = copyn(inclp->incllen = endcd-nextcd , nextcd);
293 else
294 inclp->incllinp = 0;
295 }
296 nextcd = NULL;
297
298 if(++nincl >= MAXINCLUDES)
299 Fatal("includes nested too deep");
300 if(name[0] == '\0')
301 fp = stdin;
302 else if(name[0] == '/' || inclp == NULL
303#ifdef MSDOS
304 || name[0] == '\\'
305 || name[1] == ':'
306#endif
307 )
308 fp = fopen(name, textread);
309 else {
310 lastslash = NULL;
311 s = s0 = inclp->inclname;
312#ifdef MSDOS
313 if (s[1] == ':')
314 lastslash = s + 1;
315#endif
316 for(; *s ; ++s)
317 if(*s == '/'
318#ifdef MSDOS
319 || *s == '\\'
320#endif
321 )
322 lastslash = s;
323 if(lastslash) {
324 k = lastslash - s0 + 1;
325 temp = Alloc(k + strlen(name) + 1);
326 strncpy(temp, s0, k);
327 strcpy(temp+k, name);
328 name = temp;
329 }
330 fp = fopen(name, textread);
331 }
332 if (fp)
333 {
334 t = inclp;
335 inclp = ALLOC(Inclfile);
336 inclp->inclnext = t;
337 prevlin = thislin = 0;
338 infname = inclp->inclname = name;
339 infile = inclp->inclfp = fp;
340 }
341 else
342 {
343 fprintf(diagfile, "Cannot open file %s\n", name);
344 done(1);
345 }
346}
347
348
349
350
351LOCAL popinclude()
352{
353 struct Inclfile *t;
354 register char *p;
355 register int k;
356
357 if(infile != stdin)
358 clf(&infile, infname, 1); /* Close the input file */
359 free(infname);
360
361 --nincl;
362 t = inclp->inclnext;
363 free( (charptr) inclp);
364 inclp = t;
365 if(inclp == NULL) {
366 infname = 0;
367 return(NO);
368 }
369
370 infile = inclp->inclfp;
371 infname = inclp->inclname;
372 prevlin = thislin = inclp->incllno;
373 code = inclp->inclcode;
374 stno = nxtstno = inclp->inclstno;
375 if(inclp->incllinp)
376 {
377 endcd = nextcd = sbuf;
378 k = inclp->incllen;
379 p = inclp->incllinp;
380 while(--k >= 0)
381 *endcd++ = *p++;
382 free( (charptr) (inclp->incllinp) );
383 }
384 else
385 nextcd = NULL;
386 return(YES);
387}
388
389
390static char *lastfile = "??", *lastfile0 = "?";
391static char fbuf[P1_FILENAME_MAX];
392
393void p1_line_number (line_number)
394long line_number;
395{
396 if (lastfile != lastfile0) {
397 p1puts(P1_FILENAME, fbuf);
398 lastfile0 = lastfile;
399 }
400 fprintf(pass1_file, "%d: %ld\n", P1_SET_LINE, line_number);
401 }
402
403 static void
404putlineno()
405{
406 static long lastline;
407 extern int gflag;
408 register char *s0, *s1;
409
410 if (gflag) {
411 if (lastline)
412 p1_line_number(lastline);
413 lastline = firstline;
414 if (lastfile != infname)
415 if (lastfile = infname) {
416 strncpy(fbuf, lastfile, sizeof(fbuf));
417 fbuf[sizeof(fbuf)-1] = 0;
418 }
419 else
420 fbuf[0] = 0;
421 }
422 if (addftnsrc) {
423 if (laststb && *laststb) {
424 for(s1 = laststb; *s1; s1++) {
425 for(s0 = s1; *s1 != '\n'; s1++)
426 if (*s1 == '*' && s1[1] == '/')
427 *s1 = '+';
428 *s1 = 0;
429 p1puts(P1_FORTRAN, s0);
430 }
431 *laststb = 0; /* prevent trouble after EOF */
432 }
433 laststb = stb0;
434 }
435 }
436
437
438yylex()
439{
440 static int tokno;
441 int retval;
442
443 switch(lexstate)
444 {
445 case NEWSTMT : /* need a new statement */
446 retval = getcds();
447 putlineno();
448 if(retval == STEOF) {
449 retval = SEOF;
450 break;
451 } /* if getcds() == STEOF */
452 crunch();
453 tokno = 0;
454 lexstate = FIRSTTOKEN;
455 yystno = stno;
456 stno = nxtstno;
457 toklen = 0;
458 retval = SLABEL;
459 break;
460
461first:
462 case FIRSTTOKEN : /* first step on a statement */
463 analyz();
464 lexstate = OTHERTOKEN;
465 tokno = 1;
466 retval = stkey;
467 break;
468
469 case OTHERTOKEN : /* return next token */
470 if(nextch > lastch)
471 goto reteos;
472 ++tokno;
473 if( (stkey==SLOGIF || stkey==SELSEIF) && parlev==0 && tokno>3)
474 goto first;
475
476 if(stkey==SASSIGN && tokno==3 && nextch<lastch &&
477 nextch[0]=='t' && nextch[1]=='o')
478 {
479 nextch+=2;
480 retval = STO;
481 break;
482 }
483 retval = gettok();
484 break;
485
486reteos:
487 case RETEOS:
488 lexstate = NEWSTMT;
489 retval = SEOS;
490 break;
491 default:
492 fatali("impossible lexstate %d", lexstate);
493 break;
494 }
495
496 if (retval == SEOF)
497 flush_comments ();
498
499 return retval;
500}
501
502 LOCAL void
503contmax()
504{
505 lineno = thislin;
506 many("continuation lines", 'C', maxcontin);
507 }
508
509/* Get Cards.
510
511 Returns STEOF or STINITIAL, never STCONTINUE. Any continuation cards get
512merged into one long card (hence the size of the buffer named sbuf) */
513
514 LOCAL int
515getcds()
516{
517 register char *p, *q;
518
519 flush_comments ();
520top:
521 if(nextcd == NULL)
522 {
523 code = getcd( nextcd = sbuf, 1 );
524 stno = nxtstno;
525 prevlin = thislin;
526 }
527 if(code == STEOF)
528 if( popinclude() )
529 goto top;
530 else
531 return(STEOF);
532
533 if(code == STCONTINUE)
534 {
535 lineno = thislin;
536 nextcd = NULL;
537 goto top;
538 }
539
540/* Get rid of unused space at the head of the buffer */
541
542 if(nextcd > sbuf)
543 {
544 q = nextcd;
545 p = sbuf;
546 while(q < endcd)
547 *p++ = *q++;
548 endcd = p;
549 }
550
551/* Be aware that the input (i.e. the string at the address nextcd) is NOT
552 NULL-terminated */
553
554/* This loop merges all continuations into one long statement, AND puts the next
555 card to be read at the end of the buffer (i.e. it stores the look-ahead card
556 when there's room) */
557
558 ncont = 0;
559 for(;;) {
560 nextcd = endcd;
561 if (ncont >= maxcont || nextcd+66 > send)
562 contmax();
563 linestart[ncont++] = nextcd;
564 if ((code = getcd(nextcd,0)) != STCONTINUE)
565 break;
566 if (ncont == 20 && noextflag) {
567 lineno = thislin;
568 errext("more than 19 continuation lines");
569 }
570 }
571 nextch = sbuf;
572 lastch = nextcd - 1;
573
574 lineno = prevlin;
575 prevlin = thislin;
576 return(STINITIAL);
577}
578
579 static void
580bang(a,b,c,d,e) /* save ! comments */
581 char *a, *b, *c;
582 register char *d, *e;
583{
584 char buf[COMMENT_BUFFER_SIZE + 1];
585 register char *p, *pe;
586
587 p = buf;
588 pe = buf + COMMENT_BUFFER_SIZE;
589 *pe = 0;
590 while(a < b)
591 if (!(*p++ = *a++))
592 p[-1] = 0;
593 if (b < c)
594 *p++ = '\t';
595 while(d < e) {
596 if (!(*p++ = *d++))
597 p[-1] = ' ';
598 if (p == pe) {
599 store_comment(buf);
600 p = buf;
601 }
602 }
603 if (p > buf) {
604 while(--p >= buf && *p == ' ');
605 p[1] = 0;
606 store_comment(buf);
607 }
608 }
609
610
611/* getcd - Get next input card
612
613 This function reads the next input card from global file pointer infile.
614It assumes that b points to currently empty storage somewhere in sbuf */
615
616 LOCAL int
617getcd(b, nocont)
618 register char *b;
619{
620 register int c;
621 register char *p, *bend;
622 int speclin; /* Special line - true when the line is allowed
623 to have more than 66 characters (e.g. the
624 "&" shorthand for continuation, use of a "\t"
625 to skip part of the label columns) */
626 static char a[6]; /* Statement label buffer */
627 static char *aend = a+6;
628 static char *stb, *stbend;
629 static int nst;
630 char *atend, *endcd0;
631 extern int warn72;
632 char buf72[24];
633 int amp, i;
634 char storage[COMMENT_BUFFER_SIZE + 1];
635 char *pointer;
636 long L;
637
638top:
639 endcd = b;
640 bend = b+66;
641 amp = speclin = NO;
642 atend = aend;
643
644/* Handle the continuation shorthand of "&" in the first column, which stands
645 for " x" */
646
647 if( (c = getc(infile)) == '&')
648 {
649 a[0] = c;
650 a[1] = 0;
651 a[5] = 'x';
652 amp = speclin = YES;
653 bend = send;
654 p = aend;
655 }
656
657/* Handle the Comment cards (a 'C', 'c', '*', or '!' in the first column). */
658
659 else if(comstart[c & 0xfff])
660 {
661 if (feof (infile)
662#ifdef EOF_CHAR
663 || c == EOF_CHAR
664#endif
665 )
666 return STEOF;
667
668 if (c == '#') {
669 *endcd++ = c;
670 while((c = getc(infile)) != '\n')
671 if (c == EOF)
672 return STEOF;
673 else if (endcd < bend)
674 *endcd++ = c;
675 ++thislin;
676 *endcd = 0;
677 if (b[1] == ' ')
678 p = b + 2;
679 else if (!strncmp(b,"#line ",6))
680 p = b + 6;
681 else {
682 bad_cpp:
683 errstr("Bad # line: \"%s\"", b);
684 goto top;
685 }
686 if (*p < '1' || *p > '9')
687 goto bad_cpp;
688 L = *p - '1'; /* bias down 1 */
689 while((c = *++p) >= '0' && c <= '9')
690 L = 10*L + c - '0';
691 if (c != ' ' || *++p != '"')
692 goto bad_cpp;
693 bend = p;
694 while(*++p != '"')
695 if (!*p)
696 goto bad_cpp;
697 *p = 0;
698 i = p - bend++;
699 thislin = L;
700 if (!infname || strcmp(infname, bend)) {
701 if (infname)
702 free(infname);
703 infname = Alloc(i);
704 strcpy(infname, bend);
705 if (inclp)
706 inclp->inclname = infname;
707 }
708 goto top;
709 }
710
711 storage[COMMENT_BUFFER_SIZE] = c = '\0';
712 pointer = storage;
713 while( !feof (infile) && (*pointer++ = c = getc(infile)) != '\n') {
714
715/* Handle obscure end of file conditions on many machines */
716
717 if (feof (infile) && (c == '\377' || c == EOF)) {
718 pointer--;
719 break;
720 } /* if (feof (infile)) */
721
722 if (c == '\0')
723 *(pointer - 1) = ' ';
724
725 if (pointer == &storage[COMMENT_BUFFER_SIZE]) {
726 store_comment (storage);
727 pointer = storage;
728 } /* if (pointer == BUFFER_SIZE) */
729 } /* while */
730
731 if (pointer > storage) {
732 if (c == '\n')
733
734/* Get rid of the newline */
735
736 pointer[-1] = 0;
737 else
738 *pointer = 0;
739
740 store_comment (storage);
741 } /* if */
742
743 if (feof (infile))
744 if (c != '\n') /* To allow the line index to
745 increment correctly */
746 return STEOF;
747
748 ++thislin;
749 goto top;
750 }
751
752 else if(c != EOF)
753 {
754
755/* Load buffer a with the statement label */
756
757 /* a tab in columns 1-6 skips to column 7 */
758 ungetc(c, infile);
759 for(p=a; p<aend && (c=getc(infile)) != '\n' && c!=EOF; )
760 if(c == '\t')
761
762/* The tab character translates into blank characters in the statement label */
763
764 {
765 atend = p;
766 while(p < aend)
767 *p++ = BLANK;
768 speclin = YES;
769 bend = send;
770 }
771 else
772 *p++ = c;
773 }
774
775/* By now we've read either a continuation character or the statement label
776 field */
777
778 if(c == EOF)
779 return(STEOF);
780
781/* The next 'if' block handles lines that have fewer than 7 characters */
782
783 if(c == '\n')
784 {
785 while(p < aend)
786 *p++ = BLANK;
787
788/* Blank out the buffer on lines which are not longer than 66 characters */
789
790 endcd0 = endcd;
791 if( ! speclin )
792 while(endcd < bend)
793 *endcd++ = BLANK;
794 }
795 else { /* read body of line */
796 if (warn72 & 2) {
797 speclin = YES;
798 bend = send;
799 }
800 while( endcd<bend && (c=getc(infile)) != '\n' && c!=EOF )
801 *endcd++ = c;
802 if(c == EOF)
803 return(STEOF);
804
805/* Drop any extra characters on the input card; this usually means those after
806 column 72 */
807
808 if(c != '\n')
809 {
810 i = 0;
811 while( (c=getc(infile)) != '\n' && c != EOF)
812 if (i < 23)
813 buf72[i++] = c;
814 if (warn72 && i && !speclin) {
815 buf72[i] = 0;
816 if (i >= 23)
817 strcpy(buf72+20, "...");
818 lineno = thislin + 1;
819 errstr("text after column 72: %s", buf72);
820 }
821 if(c == EOF)
822 return(STEOF);
823 }
824
825 endcd0 = endcd;
826 if( ! speclin )
827 while(endcd < bend)
828 *endcd++ = BLANK;
829 }
830
831/* The flow of control usually gets to this line (unless an earlier RETURN has
832 been taken) */
833
834 ++thislin;
835
836 /* Fortran 77 specifies that a 0 in column 6 */
837 /* does not signify continuation */
838
839 if( !isspace(a[5]) && a[5]!='0') {
840 if (!amp)
841 for(p = a; p < aend;)
842 if (*p++ == '!' && p != aend)
843 goto initcheck;
844 if (addftnsrc && stb) {
845 if (stbend > stb + 7) { /* otherwise forget col 1-6 */
846 /* kludge around funny p1gets behavior */
847 *stb++ = '$';
848 if (amp)
849 *stb++ = '&';
850 else
851 for(p = a; p < atend;)
852 *stb++ = *p++;
853 }
854 if (endcd0 - b > stbend - stb) {
855 if (stb > stbend)
856 stb = stbend;
857 endcd0 = b + (stbend - stb);
858 }
859 for(p = b; p < endcd0;)
860 *stb++ = *p++;
861 *stb++ = '\n';
862 *stb = 0;
863 }
864 if (nocont) {
865 lineno = thislin;
866 errstr("illegal continuation card (starts \"%.6s\")",a);
867 }
868 else if (!amp && strncmp(a," ",5)) {
869 lineno = thislin;
870 errstr("labeled continuation line (starts \"%.6s\")",a);
871 }
872 return(STCONTINUE);
873 }
874initcheck:
875 for(p=a; p<atend; ++p)
876 if( !isspace(*p) ) {
877 if (*p++ != '!')
878 goto initline;
879 bang(p, atend, aend, b, endcd);
880 goto top;
881 }
882 for(p = b ; p<endcd ; ++p)
883 if( !isspace(*p) ) {
884 if (*p++ != '!')
885 goto initline;
886 bang(a, a, a, p, endcd);
887 goto top;
888 }
889
890/* Skip over blank cards by reading the next one right away */
891
892 goto top;
893
894initline:
895 if (addftnsrc) {
896 nst = (nst+1)%3;
897 if (!laststb && stb0)
898 laststb = stb0;
899 stb0 = stb = stbuf[nst];
900 *stb++ = '$'; /* kludge around funny p1gets behavior */
901 stbend = stb + sizeof(stbuf[0])-2;
902 for(p = a; p < atend;)
903 *stb++ = *p++;
904 if (atend < aend)
905 *stb++ = '\t';
906 for(p = b; p < endcd0;)
907 *stb++ = *p++;
908 *stb++ = '\n';
909 *stb = 0;
910 }
911
912/* Set nxtstno equal to the integer value of the statement label */
913
914 nxtstno = 0;
915 bend = a + 5;
916 for(p = a ; p < bend ; ++p)
917 if( !isspace(*p) )
918 if(isdigit(*p))
919 nxtstno = 10*nxtstno + (*p - '0');
920 else if (*p == '!') {
921 if (!addftnsrc)
922 bang(p+1,atend,aend,b,endcd);
923 endcd = b;
924 break;
925 }
926 else {
927 lineno = thislin;
928 errstr(
929 "nondigit in statement label field \"%.5s\"", a);
930 nxtstno = 0;
931 break;
932 }
933 firstline = thislin;
934 return(STINITIAL);
935}
936
937
938/* crunch -- deletes all space characters, folds the backslash chars and
939 Hollerith strings, quotes the Fortran strings */
940
941 LOCAL void
942crunch()
943{
944 register char *i, *j, *j0, *j1, *prvstr;
945 int k, ten, nh, nh0, quote;
946
947 /* i is the next input character to be looked at
948 j is the next output character */
949
950 new_dcl = needwkey = parlev = parseen = 0;
951 expcom = 0; /* exposed ','s */
952 expeql = 0; /* exposed equal signs */
953 j = sbuf;
954 prvstr = sbuf;
955 k = 0;
956 for(i=sbuf ; i<=lastch ; ++i)
957 {
958 if(isspace(*i) )
959 continue;
960 if (*i == '!') {
961 while(i >= linestart[k])
962 if (++k >= maxcont)
963 contmax();
964 j0 = linestart[k];
965 if (!addftnsrc)
966 bang(sbuf,sbuf,sbuf,i+1,j0);
967 i = j0-1;
968 continue;
969 }
970
971/* Keep everything in a quoted string */
972
973 if(*i=='\'' || *i=='"')
974 {
975 int len = 0;
976
977 quote = *i;
978 *j = MYQUOTE; /* special marker */
979 for(;;)
980 {
981 if(++i > lastch)
982 {
983 err("unbalanced quotes; closing quote supplied");
984 if (j >= lastch)
985 j = lastch - 1;
986 break;
987 }
988 if(*i == quote)
989 if(i<lastch && i[1]==quote) ++i;
990 else break;
991 else if(*i=='\\' && i<lastch && use_bs) {
992 ++i;
993 *i = escapes[*(unsigned char *)i];
994 }
995 if (len < MAXTOKENLEN)
996 *++j = *i;
997 else if (len == MAXTOKENLEN)
998 erri
999 ("String too long, truncating to %d chars", MAXTOKENLEN);
1000 len++;
1001 } /* for (;;) */
1002
1003 j[1] = MYQUOTE;
1004 j += 2;
1005 prvstr = j;
1006 }
1007 else if( (*i=='h' || *i=='H') && j>prvstr) /* test for Hollerith strings */
1008 {
1009 j0 = j - 1;
1010 if( ! isdigit(*j0)) goto copychar;
1011 nh = *j0 - '0';
1012 ten = 10;
1013 j1 = prvstr;
1014 if (j1+4 < j)
1015 j1 = j-4;
1016 for(;;) {
1017 if (j0-- <= j1)
1018 goto copychar;
1019 if( ! isdigit(*j0 ) ) break;
1020 nh += ten * (*j0-'0');
1021 ten*=10;
1022 }
1023 /* a hollerith must be preceded by a punctuation mark.
1024 '*' is possible only as repetition factor in a data statement
1025 not, in particular, in character*2h
1026*/
1027
1028 if( !(*j0=='*'&&sbuf[0]=='d') && *j0!='/'
1029 && *j0!='(' && *j0!=',' && *j0!='=' && *j0!='.')
1030 goto copychar;
1031 nh0 = nh;
1032 if(i+nh > lastch || nh > MAXTOKENLEN)
1033 {
1034 erri("%dH too big", nh);
1035 nh = lastch - i;
1036 if (nh > MAXTOKENLEN)
1037 nh = MAXTOKENLEN;
1038 nh0 = -1;
1039 }
1040 j0[1] = MYQUOTE; /* special marker */
1041 j = j0 + 1;
1042 while(nh-- > 0)
1043 {
1044 if (++i > lastch) {
1045 hol_overflow:
1046 if (nh0 >= 0)
1047 erri("escapes make %dH too big",
1048 nh0);
1049 break;
1050 }
1051 if(*i == '\\' && use_bs) {
1052 if (++i > lastch)
1053 goto hol_overflow;
1054 *i = escapes[*(unsigned char *)i];
1055 }
1056 *++j = *i;
1057 }
1058 j[1] = MYQUOTE;
1059 j+=2;
1060 prvstr = j;
1061 }
1062 else {
1063 if(*i == '(') parseen = ++parlev;
1064 else if(*i == ')') --parlev;
1065 else if(parlev == 0)
1066 if(*i == '=') expeql = 1;
1067 else if(*i == ',') expcom = 1;
1068copychar: /*not a string or space -- copy, shifting case if necessary */
1069 if(shiftcase && isupper(*i))
1070 *j++ = tolower(*i);
1071 else *j++ = *i;
1072 }
1073 }
1074 lastch = j - 1;
1075 nextch = sbuf;
1076}
1077
1078 LOCAL void
1079analyz()
1080{
1081 register char *i;
1082
1083 if(parlev != 0)
1084 {
1085 err("unbalanced parentheses, statement skipped");
1086 stkey = SUNKNOWN;
1087 lastch = sbuf - 1; /* prevent double error msg */
1088 return;
1089 }
1090 if(nextch+2<=lastch && nextch[0]=='i' && nextch[1]=='f' && nextch[2]=='(')
1091 {
1092 /* assignment or if statement -- look at character after balancing paren */
1093 parlev = 1;
1094 for(i=nextch+3 ; i<=lastch; ++i)
1095 if(*i == (MYQUOTE))
1096 {
1097 while(*++i != MYQUOTE)
1098 ;
1099 }
1100 else if(*i == '(')
1101 ++parlev;
1102 else if(*i == ')')
1103 {
1104 if(--parlev == 0)
1105 break;
1106 }
1107 if(i >= lastch)
1108 stkey = SLOGIF;
1109 else if(i[1] == '=')
1110 stkey = SLET;
1111 else if( isdigit(i[1]) )
1112 stkey = SARITHIF;
1113 else stkey = SLOGIF;
1114 if(stkey != SLET)
1115 nextch += 2;
1116 }
1117 else if(expeql) /* may be an assignment */
1118 {
1119 if(expcom && nextch<lastch &&
1120 nextch[0]=='d' && nextch[1]=='o')
1121 {
1122 stkey = SDO;
1123 nextch += 2;
1124 }
1125 else stkey = SLET;
1126 }
1127 else if (parseen && nextch + 7 < lastch
1128 && nextch[2] != 'u' /* screen out "double..." early */
1129 && nextch[0] == 'd' && nextch[1] == 'o'
1130 && ((nextch[2] >= '0' && nextch[2] <= '9')
1131 || nextch[2] == ','
1132 || nextch[2] == 'w'))
1133 {
1134 stkey = SDO;
1135 nextch += 2;
1136 needwkey = 1;
1137 }
1138 /* otherwise search for keyword */
1139 else {
1140 stkey = getkwd();
1141 if(stkey==SGOTO && lastch>=nextch)
1142 if(nextch[0]=='(')
1143 stkey = SCOMPGOTO;
1144 else if(isalpha_(* USC nextch))
1145 stkey = SASGOTO;
1146 }
1147 parlev = 0;
1148}
1149
1150
1151
1152 LOCAL int
1153getkwd()
1154{
1155 register char *i, *j;
1156 register struct Keylist *pk, *pend;
1157 int k;
1158
1159 if(! isalpha_(* USC nextch) )
1160 return(SUNKNOWN);
1161 k = letter(nextch[0]);
1162 if(pk = keystart[k])
1163 for(pend = keyend[k] ; pk<=pend ; ++pk )
1164 {
1165 i = pk->keyname;
1166 j = nextch;
1167 while(*++i==*++j && *i!='\0')
1168 ;
1169 if(*i=='\0' && j<=lastch+1)
1170 {
1171 nextch = j;
1172 if(no66flag && pk->notinf66)
1173 errstr("Not a Fortran 66 keyword: %s",
1174 pk->keyname);
1175 return(pk->keyval);
1176 }
1177 }
1178 return(SUNKNOWN);
1179}
1180
1181initkey()
1182{
1183 register struct Keylist *p;
1184 register int i,j;
1185 register char *s;
1186
1187 for(i = 0 ; i<26 ; ++i)
1188 keystart[i] = NULL;
1189
1190 for(p = keys ; p->keyname ; ++p) {
1191 j = letter(p->keyname[0]);
1192 if(keystart[j] == NULL)
1193 keystart[j] = p;
1194 keyend[j] = p;
1195 }
1196 i = (maxcontin + 2) * 66;
1197 sbuf = (char *)ckalloc(i + 70);
1198 send = sbuf + i;
1199 maxcont = maxcontin + 1;
1200 linestart = (char **)ckalloc(maxcont*sizeof(char*));
1201 comstart['c'] = comstart['C'] = comstart['*'] = comstart['!'] =
1202 comstart['#'] = 1;
1203#ifdef EOF_CHAR
1204 comstart[EOF_CHAR] = 1;
1205#endif
1206 s = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_";
1207 while(i = *s++)
1208 anum_buf[i] = 1;
1209 s = "0123456789";
1210 while(i = *s++)
1211 anum_buf[i] = 2;
1212 }
1213
1214 LOCAL int
1215hexcheck(key)
1216 int key;
1217{
1218 register int radix;
1219 register char *p;
1220 char *kind;
1221
1222 switch(key) {
1223 case 'z':
1224 case 'Z':
1225 case 'x':
1226 case 'X':
1227 radix = 16;
1228 key = SHEXCON;
1229 kind = "hexadecimal";
1230 break;
1231 case 'o':
1232 case 'O':
1233 radix = 8;
1234 key = SOCTCON;
1235 kind = "octal";
1236 break;
1237 case 'b':
1238 case 'B':
1239 radix = 2;
1240 key = SBITCON;
1241 kind = "binary";
1242 break;
1243 default:
1244 err("bad bit identifier");
1245 return(SNAME);
1246 }
1247 for(p = token; *p; p++)
1248 if (hextoi(*p) >= radix) {
1249 errstr("invalid %s character", kind);
1250 break;
1251 }
1252 return key;
1253 }
1254
1255/* gettok -- moves the right amount of text from nextch into the token
1256 buffer. token initially contains garbage (leftovers from the prev token) */
1257
1258 LOCAL int
1259gettok()
1260{
1261int havdot, havexp, havdbl;
1262 int radix, val;
1263 struct Punctlist *pp;
1264 struct Dotlist *pd;
1265 register int ch;
1266
1267 char *i, *j, *n1, *p;
1268
1269 ch = * USC nextch;
1270 if(ch == (MYQUOTE))
1271 {
1272 ++nextch;
1273 p = token;
1274 while(*nextch != MYQUOTE)
1275 *p++ = *nextch++;
1276 toklen = p - token;
1277 *p = 0;
1278 /* allow octal, binary, hex constants of the form 'abc'x (etc.) */
1279 if (++nextch <= lastch && isalpha_(val = * USC nextch)) {
1280 ++nextch;
1281 return hexcheck(val);
1282 }
1283 return (SHOLLERITH);
1284 }
1285
1286 if(needkwd)
1287 {
1288 needkwd = 0;
1289 return( getkwd() );
1290 }
1291
1292 for(pp=puncts; pp->punchar; ++pp)
1293 if(ch == pp->punchar) {
1294 val = pp->punval;
1295 if (++nextch <= lastch)
1296 switch(ch) {
1297 case '/':
1298 if (*nextch == '/') {
1299 nextch++;
1300 val = SCONCAT;
1301 }
1302 else if (new_dcl && parlev == 0)
1303 val = SSLASHD;
1304 return val;
1305 case '*':
1306 if (*nextch == '*') {
1307 nextch++;
1308 return SPOWER;
1309 }
1310 break;
1311 case '<':
1312 if (*nextch == '=') {
1313 nextch++;
1314 val = SLE;
1315 }
1316 if (*nextch == '>') {
1317 nextch++;
1318 val = SNE;
1319 }
1320 goto extchk;
1321 case '=':
1322 if (*nextch == '=') {
1323 nextch++;
1324 val = SEQ;
1325 goto extchk;
1326 }
1327 break;
1328 case '>':
1329 if (*nextch == '=') {
1330 nextch++;
1331 val = SGE;
1332 }
1333 extchk:
1334 NOEXT("Fortran 8x comparison operator");
1335 return val;
1336 }
1337 else if (ch == '/' && new_dcl && parlev == 0)
1338 return SSLASHD;
1339 switch(val) {
1340 case SLPAR:
1341 ++parlev;
1342 break;
1343 case SRPAR:
1344 --parlev;
1345 }
1346 return(val);
1347 }
1348 if(ch == '.')
1349 if(nextch >= lastch) goto badchar;
1350 else if(isdigit(nextch[1])) goto numconst;
1351 else {
1352 for(pd=dots ; (j=pd->dotname) ; ++pd)
1353 {
1354 for(i=nextch+1 ; i<=lastch ; ++i)
1355 if(*i != *j) break;
1356 else if(*i != '.') ++j;
1357 else {
1358 nextch = i+1;
1359 return(pd->dotval);
1360 }
1361 }
1362 goto badchar;
1363 }
1364 if( isalpha_(ch) )
1365 {
1366 p = token;
1367 *p++ = *nextch++;
1368 while(nextch<=lastch)
1369 if( isalnum_(* USC nextch) )
1370 *p++ = *nextch++;
1371 else break;
1372 toklen = p - token;
1373 *p = 0;
1374 if (needwkey) {
1375 needwkey = 0;
1376 if (toklen == 5
1377 && nextch <= lastch && *nextch == '(' /*)*/
1378 && !strcmp(token,"while"))
1379 return(SWHILE);
1380 }
1381 if(inioctl && nextch<=lastch && *nextch=='=')
1382 {
1383 ++nextch;
1384 return(SNAMEEQ);
1385 }
1386 if(toklen>8 && eqn(8,token,"function")
1387 && isalpha_(* USC (token+8)) &&
1388 nextch<lastch && nextch[0]=='(' &&
1389 (nextch[1]==')' || isalpha_(* USC (nextch+1))) )
1390 {
1391 nextch -= (toklen - 8);
1392 return(SFUNCTION);
1393 }
1394
1395 if(toklen > 50)
1396 {
1397 char buff[100];
1398 sprintf(buff, toklen >= 60
1399 ? "name %.56s... too long, truncated to %.*s"
1400 : "name %s too long, truncated to %.*s",
1401 token, 50, token);
1402 err(buff);
1403 toklen = 50;
1404 token[50] = '\0';
1405 }
1406 if(toklen==1 && *nextch==MYQUOTE) {
1407 val = token[0];
1408 ++nextch;
1409 for(p = token ; *nextch!=MYQUOTE ; )
1410 *p++ = *nextch++;
1411 ++nextch;
1412 toklen = p - token;
1413 *p = 0;
1414 return hexcheck(val);
1415 }
1416 return(SNAME);
1417 }
1418
1419 if (isdigit(ch)) {
1420
1421 /* Check for NAG's special hex constant */
1422
1423 if (nextch[1] == '#' && nextch < lastch
1424 || nextch[2] == '#' && isdigit(nextch[1]
1425 && lastch - nextch >= 2)) {
1426
1427 radix = atoi (nextch);
1428 if (*++nextch != '#')
1429 nextch++;
1430 if (radix != 2 && radix != 8 && radix != 16) {
1431 erri("invalid base %d for constant, defaulting to hex",
1432 radix);
1433 radix = 16;
1434 } /* if */
1435 if (++nextch > lastch)
1436 goto badchar;
1437 for (p = token; hextoi(*nextch) < radix;) {
1438 *p++ = *nextch++;
1439 if (nextch > lastch)
1440 break;
1441 }
1442 toklen = p - token;
1443 *p = 0;
1444 return (radix == 16) ? SHEXCON : ((radix == 8) ? SOCTCON :
1445 SBITCON);
1446 }
1447 }
1448 else
1449 goto badchar;
1450numconst:
1451 havdot = NO;
1452 havexp = NO;
1453 havdbl = NO;
1454 for(n1 = nextch ; nextch<=lastch ; ++nextch)
1455 {
1456 if(*nextch == '.')
1457 if(havdot) break;
1458 else if(nextch+2<=lastch && isalpha_(* USC (nextch+1))
1459 && isalpha_(* USC (nextch+2)))
1460 break;
1461 else havdot = YES;
1462 else if( !intonly && (*nextch=='d' || *nextch=='e') )
1463 {
1464 p = nextch;
1465 havexp = YES;
1466 if(*nextch == 'd')
1467 havdbl = YES;
1468 if(nextch<lastch)
1469 if(nextch[1]=='+' || nextch[1]=='-')
1470 ++nextch;
1471 if( ! isdigit(*++nextch) )
1472 {
1473 nextch = p;
1474 havdbl = havexp = NO;
1475 break;
1476 }
1477 for(++nextch ;
1478 nextch<=lastch && isdigit(* USC nextch);
1479 ++nextch);
1480 break;
1481 }
1482 else if( ! isdigit(* USC nextch) )
1483 break;
1484 }
1485 p = token;
1486 i = n1;
1487 while(i < nextch)
1488 *p++ = *i++;
1489 toklen = p - token;
1490 *p = 0;
1491 if(havdbl) return(SDCON);
1492 if(havdot || havexp) return(SRCON);
1493 return(SICON);
1494badchar:
1495 sbuf[0] = *nextch++;
1496 return(SUNKNOWN);
1497}
1498
1499/* Comment buffering code */
1500
1501 static void
1502store_comment(str)
1503 char *str;
1504{
1505 int len;
1506 comment_buf *ncb;
1507
1508 if (nextcd == sbuf) {
1509 flush_comments();
1510 p1_comment(str);
1511 return;
1512 }
1513 len = strlen(str) + 1;
1514 if (cbnext + len > cblast) {
1515 if (!cbcur || !(ncb = cbcur->next)) {
1516 ncb = (comment_buf *) Alloc(sizeof(comment_buf));
1517 if (cbcur) {
1518 cbcur->last = cbnext;
1519 cbcur->next = ncb;
1520 }
1521 else {
1522 cbfirst = ncb;
1523 cbinit = ncb->buf;
1524 }
1525 ncb->next = 0;
1526 }
1527 cbcur = ncb;
1528 cbnext = ncb->buf;
1529 cblast = cbnext + COMMENT_BUF_STORE;
1530 }
1531 strcpy(cbnext, str);
1532 cbnext += len;
1533 }
1534
1535 static void
1536flush_comments()
1537{
1538 register char *s, *s1;
1539 register comment_buf *cb;
1540 if (cbnext == cbinit)
1541 return;
1542 cbcur->last = cbnext;
1543 for(cb = cbfirst;; cb = cb->next) {
1544 for(s = cb->buf; s < cb->last; s = s1) {
1545 /* compute s1 = new s value first, since */
1546 /* p1_comment may insert nulls into s */
1547 s1 = s + strlen(s) + 1;
1548 p1_comment(s);
1549 }
1550 if (cb == cbcur)
1551 break;
1552 }
1553 cbcur = cbfirst;
1554 cbnext = cbinit;
1555 cblast = cbnext + COMMENT_BUF_STORE;
1556 }
1557
1558 void
1559unclassifiable()
1560{
1561 register char *s, *se;
1562
1563 s = sbuf;
1564 se = lastch;
1565 if (se < sbuf)
1566 return;
1567 lastch = s - 1;
1568 if (se - s > 10)
1569 se = s + 10;
1570 for(; s < se; s++)
1571 if (*s == MYQUOTE) {
1572 se = s;
1573 break;
1574 }
1575 *se = 0;
1576 errstr("unclassifiable statement (starts \"%s\")", sbuf);
1577 }