1 /****************************************************************
2 Copyright 1990 by AT&T Bell Laboratories and Bellcore.
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.
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
22 ****************************************************************/
46 LOCAL int stkey; /* Type of the current statement (DO, END, IF, etc) */
47 extern char token[]; /* holds the actual token text */
53 LOCAL long int nxtstno; /* Statement label */
54 LOCAL int parlev; /* Parentheses level */
60 LOCAL char *nextcd = NULL;
64 LOCAL int code; /* Card type; INITIAL, CONTINUE or EOF */
65 LOCAL int lexstate = NEWSTMT;
66 LOCAL char sbuf[1390]; /* Main buffer for Fortran source input. The number
67 comes from lines of at most 66 characters, with at
68 most 20 continuation cards (or something); this is
69 part of the defn of the standard */
70 LOCAL char *send = sbuf+20*66;
71 LOCAL int nincl = 0; /* Current number of include files */
73 LOCAL char *laststb, *stb0;
75 #define CONTMAX 100 /* max continuation lines for ! processing */
76 char *linestart[CONTMAX];
78 LOCAL char comstart[256];
79 #define USC (unsigned char *)
81 static char anum_buf[256];
82 #define isalnum_(x) anum_buf[x]
83 #define isalpha_(x) (anum_buf[x] == 1)
85 #define COMMENT_BUF_STORE 4088
87 typedef struct comment_buf {
88 struct comment_buf *next;
90 char buf[COMMENT_BUF_STORE];
92 static comment_buf *cbfirst, *cbcur;
93 static char *cbinit, *cbnext, *cblast;
94 static void flush_comments();
97 /* Comment buffering data
99 Comments are kept in a list until the statement before them has
100 been parsed. This list is implemented with the above comment_buf
101 structure and the pointers cbnext and cblast.
103 The comments are stored with terminating NULL, and no other
104 intervening space. The last few bytes of each block are likely to
108 /* struct Inclfile holds the state information for each include file */
111 struct Inclfile *inclnext;
121 LOCAL struct Inclfile *inclp = NULL;
122 LOCAL struct Keylist {
127 LOCAL struct Punctlist {
131 LOCAL struct Fmtlist {
139 LOCAL struct Keylist *keystart[26], *keyend[26];
141 /* KEYWORD AND SPECIAL CHARACTER TABLES
144 static struct Punctlist puncts[ ] =
160 LOCAL struct Dotlist dots[ ] =
177 LOCAL struct Keylist keys[ ] =
179 { "assign", SASSIGN },
180 { "automatic", SAUTOMATIC, YES },
181 { "backspace", SBACKSPACE },
182 { "blockdata", SBLOCK },
184 { "character", SCHARACTER, YES },
185 { "close", SCLOSE, YES },
186 { "common", SCOMMON },
187 { "complex", SCOMPLEX },
188 { "continue", SCONTINUE },
190 { "dimension", SDIMENSION },
191 { "doubleprecision", SDOUBLE },
192 { "doublecomplex", SDCOMPLEX, YES },
193 { "elseif", SELSEIF, YES },
194 { "else", SELSE, YES },
195 { "endfile", SENDFILE },
196 { "endif", SENDIF, YES },
197 { "enddo", SENDDO, YES },
199 { "entry", SENTRY, YES },
200 { "equivalence", SEQUIV },
201 { "external", SEXTERNAL },
202 { "format", SFORMAT },
203 { "function", SFUNCTION },
205 { "implicit", SIMPLICIT, YES },
206 { "include", SINCLUDE, YES },
207 { "inquire", SINQUIRE, YES },
208 { "intrinsic", SINTRINSIC, YES },
209 { "integer", SINTEGER },
210 { "logical", SLOGICAL },
211 { "namelist", SNAMELIST, YES },
212 { "none", SUNDEFINED, YES },
213 { "open", SOPEN, YES },
214 { "parameter", SPARAM, YES },
217 { "program", SPROGRAM, YES },
218 { "punch", SPUNCH, YES },
221 { "return", SRETURN },
222 { "rewind", SREWIND },
223 { "save", SSAVE, YES },
224 { "static", SSTATIC, YES },
226 { "subroutine", SSUBROUTINE },
227 { "then", STHEN, YES },
228 { "undefined", SUNDEFINED, YES },
229 { "while", SWHILE, YES },
234 LOCAL void analyz(), crunch(), store_comment();
235 LOCAL int getcd(), getcds(), getkwd(), gettok();
249 /* throw away the rest of the current line */
260 *n = (lastch - nextch) + 1;
276 inclp->incllno = thislin;
277 inclp->inclcode = code;
278 inclp->inclstno = nxtstno;
280 inclp->incllinp = copyn(inclp->incllen = endcd-nextcd , nextcd);
286 if(++nincl >= MAXINCLUDES)
287 Fatal("includes nested too deep");
291 fp = fopen(name, textread);
295 inclp = ALLOC(Inclfile);
297 prevlin = thislin = 0;
298 infname = inclp->inclname = name;
299 infile = inclp->inclfp = fp;
303 fprintf(diagfile, "Cannot open file %s\n", name);
318 clf(&infile, infname, 1); /* Close the input file */
323 free( (charptr) inclp);
330 infile = inclp->inclfp;
331 infname = inclp->inclname;
332 prevlin = thislin = inclp->incllno;
333 code = inclp->inclcode;
334 stno = nxtstno = inclp->inclstno;
337 endcd = nextcd = sbuf;
342 free( (charptr) (inclp->incllinp) );
352 static long lastline;
353 static char *lastfile = "??", *lastfile0 = "?";
354 static char fbuf[P1_FILENAME_MAX];
356 register char *s0, *s1;
360 if (lastfile != lastfile0) {
361 p1puts(P1_FILENAME, fbuf);
362 lastfile0 = lastfile;
364 p1_line_number(lastline);
366 lastline = firstline;
367 if (lastfile != infname)
368 if (lastfile = infname) {
369 strncpy(fbuf, lastfile, sizeof(fbuf));
370 fbuf[sizeof(fbuf)-1] = 0;
376 if (laststb && *laststb) {
377 for(s1 = laststb; *s1; s1++) {
378 for(s0 = s1; *s1 != '\n'; s1++)
379 if (*s1 == '*' && s1[1] == '/')
382 p1puts(P1_FORTRAN, s0);
384 *laststb = 0; /* prevent trouble after EOF */
398 case NEWSTMT : /* need a new statement */
401 if(retval == STEOF) {
404 } /* if getcds() == STEOF */
407 lexstate = FIRSTTOKEN;
415 case FIRSTTOKEN : /* first step on a statement */
417 lexstate = OTHERTOKEN;
422 case OTHERTOKEN : /* return next token */
426 if( (stkey==SLOGIF || stkey==SELSEIF) && parlev==0 && tokno>3)
429 if(stkey==SASSIGN && tokno==3 && nextch<lastch &&
430 nextch[0]=='t' && nextch[1]=='o')
445 fatali("impossible lexstate %d", lexstate);
457 Returns STEOF or STINITIAL, never STCONTINUE. Any continuation cards get
458 merged into one long card (hence the size of the buffer named sbuf) */
463 register char *p, *q;
469 code = getcd( nextcd = sbuf, 1 );
479 if(code == STCONTINUE)
486 /* Get rid of unused space at the head of the buffer */
497 /* Be aware that the input (i.e. the string at the address nextcd) is NOT
500 /* This loop merges all continuations into one long statement, AND puts the next
501 card to be read at the end of the buffer (i.e. it stores the look-ahead card
502 when there's room) */
508 linestart[ncont++] = nextcd;
510 while(nextcd+66<=send && (code = getcd(nextcd,0))==STCONTINUE);
514 /* Handle buffer overflow by zeroing the 'next' pointer (nextcd) so that
515 the top of this function will initialize it next time it is called */
525 bang(a,b,c,d,e) /* save ! comments */
527 register char *d, *e;
529 char buf[COMMENT_BUFFER_SIZE + 1];
530 register char *p, *pe;
533 pe = buf + COMMENT_BUFFER_SIZE;
549 while(--p >= buf && *p == ' ');
555 /* getcd - Get next input card
557 This function reads the next input card from global file pointer infile.
558 It assumes that b points to currently empty storage somewhere in sbuf */
565 register char *p, *bend;
566 int speclin; /* Special line - true when the line is allowed
567 to have more than 66 characters (e.g. the
568 "&" shorthand for continuation, use of a "\t"
569 to skip part of the label columns) */
570 static char a[6]; /* Statement label buffer */
571 static char *aend = a+6;
572 static char stbuf[3][P1_STMTBUFSIZE], *stb, *stbend;
574 char *atend, *endcd0;
576 char storage[COMMENT_BUFFER_SIZE + 1];
585 /* Handle the continuation shorthand of "&" in the first column, which stands
588 if( (c = getc(infile)) == '&')
598 /* Handle the Comment cards (a 'C', 'c', '*', or '!' in the first column). */
600 else if(comstart[c & 0xff])
605 storage[COMMENT_BUFFER_SIZE] = c = '\0';
607 while( !feof (infile) && (*pointer++ = c = getc(infile)) != '\n') {
609 /* Handle obscure end of file conditions on many machines */
611 if (feof (infile) && (c == '\377' || c == EOF)) {
614 } /* if (feof (infile)) */
617 *(pointer - 1) = ' ';
619 if (pointer == &storage[COMMENT_BUFFER_SIZE]) {
620 store_comment (storage);
622 } /* if (pointer == BUFFER_SIZE) */
625 if (pointer > storage) {
628 /* Get rid of the newline */
634 store_comment (storage);
638 if (c != '\n') /* To allow the line index to
639 increment correctly */
649 /* Load buffer a with the statement label */
651 /* a tab in columns 1-6 skips to column 7 */
653 for(p=a; p<aend && (c=getc(infile)) != '\n' && c!=EOF; )
656 /* The tab character translates into blank characters in the statement label */
669 /* By now we've read either a continuation character or the statement label
675 /* The next 'if' block handles lines that have fewer than 7 characters */
682 /* Blank out the buffer on lines which are not longer than 66 characters */
689 else { /* read body of line */
690 while( endcd<bend && (c=getc(infile)) != '\n' && c!=EOF )
695 /* Drop any extra characters on the input card; this usually means those after
700 while( (c=getc(infile)) != '\n')
711 /* The flow of control usually gets to this line (unless an earlier RETURN has
716 /* Fortran 77 specifies that a 0 in column 6 */
717 /* does not signify continuation */
719 if( !isspace(a[5]) && a[5]!='0') {
721 for(p = a; p < aend;)
722 if (*p++ == '!' && p != aend)
724 if (addftnsrc && stb) {
725 if (stbend > stb + 7) { /* otherwise forget col 1-6 */
726 /* kludge around funny p1gets behavior */
731 for(p = a; p < atend;)
734 if (endcd0 - b > stbend - stb) {
737 endcd0 = b + (stbend - stb);
739 for(p = b; p < endcd0;)
746 errstr("illegal continuation card (starts \"%.6s\")",a);
748 else if (!amp && strncmp(a," ",5)) {
750 errstr("labeled continuation line (starts \"%.6s\")",a);
755 for(p=a; p<atend; ++p)
759 bang(p, atend, aend, b, endcd);
762 for(p = b ; p<endcd ; ++p)
766 bang(a, a, a, p, endcd);
770 /* Skip over blank cards by reading the next one right away */
777 if (!laststb && stb0)
779 stb0 = stb = stbuf[nst];
780 *stb++ = '$'; /* kludge around funny p1gets behavior */
781 stbend = stb + sizeof(stbuf[0])-2;
782 for(p = a; p < atend;)
786 for(p = b; p < endcd0;)
792 /* Set nxtstno equal to the integer value of the statement label */
796 for(p = a ; p < bend ; ++p)
799 nxtstno = 10*nxtstno + (*p - '0');
800 else if (*p == '!') {
802 bang(p+1,atend,aend,b,endcd);
809 "nondigit in statement label field \"%.5s\"", a);
818 /* crunch -- deletes all space characters, folds the backslash chars and
819 Hollerith strings, quotes the Fortran strings */
824 register char *i, *j, *j0, *j1, *prvstr;
825 int k, ten, nh, quote;
827 /* i is the next input character to be looked at
828 j is the next output character */
830 new_dcl = needwkey = parlev = parseen = 0;
831 expcom = 0; /* exposed ','s */
832 expeql = 0; /* exposed equal signs */
836 for(i=sbuf ; i<=lastch ; ++i)
841 while(i >= linestart[k])
843 Fatal("too many continuations\n");
846 bang(sbuf,sbuf,sbuf,i+1,j0);
851 /* Keep everything in a quoted string */
853 if(*i=='\'' || *i=='"')
858 *j = MYQUOTE; /* special marker */
863 err("unbalanced quotes; closing quote supplied");
869 if(i<lastch && i[1]==quote) ++i;
871 else if(*i=='\\' && i<lastch)
895 if (len + 2 < MAXTOKENLEN)
897 else if (len + 2 == MAXTOKENLEN)
899 ("String too long, truncating to %d chars", MAXTOKENLEN - 2);
907 else if( (*i=='h' || *i=='H') && j>prvstr) /* test for Hollerith strings */
910 if( ! isdigit(*j0)) goto copychar;
919 if( ! isdigit(*j0 ) ) break;
920 nh += ten * (*j0-'0');
923 /* a hollerith must be preceded by a punctuation mark.
924 '*' is possible only as repetition factor in a data statement
925 not, in particular, in character*2h
928 if( !(*j0=='*'&&sbuf[0]=='d') && *j0!='/'
929 && *j0!='(' && *j0!=',' && *j0!='=' && *j0!='.')
931 if(i+nh > lastch || nh + 2 > MAXTOKENLEN)
933 erri("%dH too big", nh);
936 j0[1] = MYQUOTE; /* special marker */
968 if(*i == '(') parseen = ++parlev;
969 else if(*i == ')') --parlev;
971 if(*i == '=') expeql = 1;
972 else if(*i == ',') expcom = 1;
973 copychar: /*not a string or space -- copy, shifting case if necessary */
974 if(shiftcase && isupper(*i))
990 err("unbalanced parentheses, statement skipped");
992 lastch = sbuf - 1; /* prevent double error msg */
995 if(nextch+2<=lastch && nextch[0]=='i' && nextch[1]=='f' && nextch[2]=='(')
997 /* assignment or if statement -- look at character after balancing paren */
999 for(i=nextch+3 ; i<=lastch; ++i)
1002 while(*++i != MYQUOTE)
1014 else if(i[1] == '=')
1016 else if( isdigit(i[1]) )
1018 else stkey = SLOGIF;
1022 else if(expeql) /* may be an assignment */
1024 if(expcom && nextch<lastch &&
1025 nextch[0]=='d' && nextch[1]=='o')
1032 else if (parseen && nextch + 7 < lastch
1033 && nextch[2] != 'u' /* screen out "double..." early */
1034 && nextch[0] == 'd' && nextch[1] == 'o'
1035 && ((nextch[2] >= '0' && nextch[2] <= '9')
1037 || nextch[2] == 'w'))
1043 /* otherwise search for keyword */
1046 if(stkey==SGOTO && lastch>=nextch)
1049 else if(isalpha(nextch[0]))
1060 register char *i, *j;
1061 register struct Keylist *pk, *pend;
1064 if(! isalpha(nextch[0]) )
1066 k = letter(nextch[0]);
1067 if(pk = keystart[k])
1068 for(pend = keyend[k] ; pk<=pend ; ++pk )
1072 while(*++i==*++j && *i!='\0')
1074 if(*i=='\0' && j<=lastch+1)
1077 if(no66flag && pk->notinf66)
1078 errstr("Not a Fortran 66 keyword: %s",
1088 register struct Keylist *p;
1092 for(i = 0 ; i<26 ; ++i)
1095 for(p = keys ; p->keyname ; ++p) {
1096 j = letter(p->keyname[0]);
1097 if(keystart[j] == NULL)
1101 comstart['c'] = comstart['C'] = comstart['*'] = comstart['!'] = 1;
1102 s = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_";
1110 /* gettok -- moves the right amount of text from nextch into the token
1111 buffer. token initially contains garbage (leftovers from the prev token) */
1116 int havdot, havexp, havdbl;
1118 struct Punctlist *pp;
1122 char *i, *j, *n1, *p;
1129 while(*nextch != MYQUOTE)
1134 return (SHOLLERITH);
1136 /* The next 40 lines or so were an early attempt to parse FORMAT
1137 statements. They have been deleted */
1139 /* Not a format statement */
1147 for(pp=puncts; pp->punchar; ++pp)
1148 if(ch == pp->punchar) {
1150 if (++nextch <= lastch)
1153 if (*nextch == '/') {
1157 else if (new_dcl && parlev == 0)
1161 if (*nextch == '*') {
1167 if (*nextch == '=') {
1171 if (*nextch == '>') {
1177 if (*nextch == '=') {
1184 if (*nextch == '=') {
1189 NOEXT("Fortran 8x comparison operator");
1192 else if (ch == '/' && new_dcl && parlev == 0)
1204 if(nextch >= lastch) goto badchar;
1205 else if(isdigit(nextch[1])) goto numconst;
1207 for(pd=dots ; (j=pd->dotname) ; ++pd)
1209 for(i=nextch+1 ; i<=lastch ; ++i)
1211 else if(*i != '.') ++j;
1223 while(nextch<=lastch)
1224 if( isalnum_(* USC nextch) )
1232 && nextch <= lastch && *nextch == '(' /*)*/
1233 && !strcmp(token,"while"))
1236 if(inioctl && nextch<=lastch && *nextch=='=')
1241 if(toklen>8 && eqn(8,token,"function") && isalpha(token[8]) &&
1242 nextch<lastch && nextch[0]=='(' &&
1243 (nextch[1]==')' || isalpha(nextch[1])) )
1245 nextch -= (toklen - 8);
1252 sprintf(buff, toklen >= 60
1253 ? "name %.56s... too long, truncated to %.*s"
1254 : "name %s too long, truncated to %.*s",
1260 if(toklen==1 && *nextch==MYQUOTE)
1279 err("bad bit identifier");
1283 for(p = token ; *nextch!=MYQUOTE ; )
1284 if( hextoi(*p++ = *nextch++) >= radix)
1286 err("invalid binary character");
1292 return( radix==16 ? SHEXCON :
1293 (radix==8 ? SOCTCON : SBITCON) );
1300 /* Check for NAG's special hex constant */
1302 if (nextch[1] == '#'
1303 || nextch[2] == '#' && isdigit(nextch[1])) {
1305 radix = atoi (nextch);
1306 if (*++nextch != '#')
1308 if (radix != 2 && radix != 8 && radix != 16) {
1309 erri("invalid base %d for constant, defaulting to hex",
1313 if (++nextch > lastch)
1315 for (p = token; hextoi(*nextch) < radix;) {
1317 if (nextch > lastch)
1322 return (radix == 16) ? SHEXCON : ((radix == 8) ? SOCTCON :
1332 for(n1 = nextch ; nextch<=lastch ; ++nextch)
1336 else if(nextch+2<=lastch && isalpha(nextch[1])
1337 && isalpha(nextch[2]))
1340 else if( !intonly && (*nextch=='d' || *nextch=='e') )
1347 if(nextch[1]=='+' || nextch[1]=='-')
1349 if( ! isdigit(*++nextch) )
1352 havdbl = havexp = NO;
1356 nextch<=lastch && isdigit(* USC nextch);
1360 else if( ! isdigit(* USC nextch) )
1369 if(havdbl) return(SDCON);
1370 if(havdot || havexp) return(SRCON);
1373 sbuf[0] = *nextch++;
1377 /* Comment buffering code */
1387 if (nextcd == sbuf) {
1392 len = strlen(str) + 1;
1393 if (cbnext + len > cblast) {
1394 if (!cbcur || !(ncb = cbcur->next)) {
1395 ncb = (comment_buf *) Alloc(sizeof(comment_buf));
1397 cbcur->last = cbnext;
1408 cblast = cbnext + COMMENT_BUF_STORE;
1410 strcpy(cbnext, str);
1417 register char *s, *s1;
1418 register comment_buf *cb;
1419 if (cbnext == cbinit)
1421 cbcur->last = cbnext;
1422 for(cb = cbfirst;; cb = cb->next) {
1423 for(s = cb->buf; s < cb->last; s = s1) {
1424 /* compute s1 = new s value first, since */
1425 /* p1_comment may insert nulls into s */
1426 s1 = s + strlen(s) + 1;
1434 cblast = cbnext + COMMENT_BUF_STORE;
1440 register char *s, *se;
1450 if (*s == MYQUOTE) {
1455 errstr("unclassifiable statment (starts \"%s\")", sbuf);