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