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[Table_size];
79 #define USC (unsigned char *)
81 static char anum_buf[Table_size];
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();
98 /* Comment buffering data
100 Comments are kept in a list until the statement before them has
101 been parsed. This list is implemented with the above comment_buf
102 structure and the pointers cbnext and cblast.
104 The comments are stored with terminating NULL, and no other
105 intervening space. The last few bytes of each block are likely to
109 /* struct Inclfile holds the state information for each include file */
112 struct Inclfile *inclnext;
122 LOCAL struct Inclfile *inclp = NULL;
140 LOCAL struct Keylist *keystart[26], *keyend[26];
142 /* KEYWORD AND SPECIAL CHARACTER TABLES
145 static struct Punctlist puncts[ ] =
161 LOCAL struct Dotlist dots[ ] =
178 LOCAL struct Keylist keys[ ] =
180 { "assign", SASSIGN },
181 { "automatic", SAUTOMATIC, YES },
182 { "backspace", SBACKSPACE },
183 { "blockdata", SBLOCK },
185 { "character", SCHARACTER, YES },
186 { "close", SCLOSE, YES },
187 { "common", SCOMMON },
188 { "complex", SCOMPLEX },
189 { "continue", SCONTINUE },
191 { "dimension", SDIMENSION },
192 { "doubleprecision", SDOUBLE },
193 { "doublecomplex", SDCOMPLEX, YES },
194 { "elseif", SELSEIF, YES },
195 { "else", SELSE, YES },
196 { "endfile", SENDFILE },
197 { "endif", SENDIF, YES },
198 { "enddo", SENDDO, YES },
200 { "entry", SENTRY, YES },
201 { "equivalence", SEQUIV },
202 { "external", SEXTERNAL },
203 { "format", SFORMAT },
204 { "function", SFUNCTION },
206 { "implicit", SIMPLICIT, YES },
207 { "include", SINCLUDE, YES },
208 { "inquire", SINQUIRE, YES },
209 { "intrinsic", SINTRINSIC, YES },
210 { "integer", SINTEGER },
211 { "logical", SLOGICAL },
212 { "namelist", SNAMELIST, YES },
213 { "none", SUNDEFINED, YES },
214 { "open", SOPEN, YES },
215 { "parameter", SPARAM, YES },
218 { "program", SPROGRAM, YES },
219 { "punch", SPUNCH, YES },
222 { "return", SRETURN },
223 { "rewind", SREWIND },
224 { "save", SSAVE, YES },
225 { "static", SSTATIC, YES },
227 { "subroutine", SSUBROUTINE },
228 { "then", STHEN, YES },
229 { "undefined", SUNDEFINED, YES },
230 { "while", SWHILE, YES },
235 LOCAL void analyz(), crunch(), store_comment();
236 LOCAL int getcd(), getcds(), getkwd(), gettok();
237 LOCAL char *stbuf[3];
242 stbuf[0] = Alloc(3*P1_STMTBUFSIZE);
243 stbuf[1] = stbuf[0] + P1_STMTBUFSIZE;
244 stbuf[2] = stbuf[1] + P1_STMTBUFSIZE;
254 /* throw away the rest of the current line */
265 *n = (lastch - nextch) + 1;
281 inclp->incllno = thislin;
282 inclp->inclcode = code;
283 inclp->inclstno = nxtstno;
285 inclp->incllinp = copyn(inclp->incllen = endcd-nextcd , nextcd);
291 if(++nincl >= MAXINCLUDES)
292 Fatal("includes nested too deep");
296 fp = fopen(name, textread);
300 inclp = ALLOC(Inclfile);
302 prevlin = thislin = 0;
303 infname = inclp->inclname = name;
304 infile = inclp->inclfp = fp;
308 fprintf(diagfile, "Cannot open file %s\n", name);
323 clf(&infile, infname, 1); /* Close the input file */
328 free( (charptr) inclp);
335 infile = inclp->inclfp;
336 infname = inclp->inclname;
337 prevlin = thislin = inclp->incllno;
338 code = inclp->inclcode;
339 stno = nxtstno = inclp->inclstno;
342 endcd = nextcd = sbuf;
347 free( (charptr) (inclp->incllinp) );
357 static long lastline;
358 static char *lastfile = "??", *lastfile0 = "?";
359 static char fbuf[P1_FILENAME_MAX];
361 register char *s0, *s1;
365 if (lastfile != lastfile0) {
366 p1puts(P1_FILENAME, fbuf);
367 lastfile0 = lastfile;
369 p1_line_number(lastline);
371 lastline = firstline;
372 if (lastfile != infname)
373 if (lastfile = infname) {
374 strncpy(fbuf, lastfile, sizeof(fbuf));
375 fbuf[sizeof(fbuf)-1] = 0;
381 if (laststb && *laststb) {
382 for(s1 = laststb; *s1; s1++) {
383 for(s0 = s1; *s1 != '\n'; s1++)
384 if (*s1 == '*' && s1[1] == '/')
387 p1puts(P1_FORTRAN, s0);
389 *laststb = 0; /* prevent trouble after EOF */
403 case NEWSTMT : /* need a new statement */
406 if(retval == STEOF) {
409 } /* if getcds() == STEOF */
412 lexstate = FIRSTTOKEN;
420 case FIRSTTOKEN : /* first step on a statement */
422 lexstate = OTHERTOKEN;
427 case OTHERTOKEN : /* return next token */
431 if( (stkey==SLOGIF || stkey==SELSEIF) && parlev==0 && tokno>3)
434 if(stkey==SASSIGN && tokno==3 && nextch<lastch &&
435 nextch[0]=='t' && nextch[1]=='o')
450 fatali("impossible lexstate %d", lexstate);
462 Returns STEOF or STINITIAL, never STCONTINUE. Any continuation cards get
463 merged into one long card (hence the size of the buffer named sbuf) */
468 register char *p, *q;
474 code = getcd( nextcd = sbuf, 1 );
484 if(code == STCONTINUE)
491 /* Get rid of unused space at the head of the buffer */
502 /* Be aware that the input (i.e. the string at the address nextcd) is NOT
505 /* This loop merges all continuations into one long statement, AND puts the next
506 card to be read at the end of the buffer (i.e. it stores the look-ahead card
507 when there's room) */
513 linestart[ncont++] = nextcd;
515 while(nextcd+66<=send && (code = getcd(nextcd,0))==STCONTINUE);
519 /* Handle buffer overflow by zeroing the 'next' pointer (nextcd) so that
520 the top of this function will initialize it next time it is called */
530 bang(a,b,c,d,e) /* save ! comments */
532 register char *d, *e;
534 char buf[COMMENT_BUFFER_SIZE + 1];
535 register char *p, *pe;
538 pe = buf + COMMENT_BUFFER_SIZE;
554 while(--p >= buf && *p == ' ');
561 /* getcd - Get next input card
563 This function reads the next input card from global file pointer infile.
564 It assumes that b points to currently empty storage somewhere in sbuf */
571 register char *p, *bend;
572 int speclin; /* Special line - true when the line is allowed
573 to have more than 66 characters (e.g. the
574 "&" shorthand for continuation, use of a "\t"
575 to skip part of the label columns) */
576 static char a[6]; /* Statement label buffer */
577 static char *aend = a+6;
578 static char *stb, *stbend;
580 char *atend, *endcd0;
582 char storage[COMMENT_BUFFER_SIZE + 1];
591 /* Handle the continuation shorthand of "&" in the first column, which stands
594 if( (c = getc(infile)) == '&')
604 /* Handle the Comment cards (a 'C', 'c', '*', or '!' in the first column). */
606 else if(comstart[c & 0xfff])
611 storage[COMMENT_BUFFER_SIZE] = c = '\0';
613 while( !feof (infile) && (*pointer++ = c = getc(infile)) != '\n') {
615 /* Handle obscure end of file conditions on many machines */
617 if (feof (infile) && (c == '\377' || c == EOF)) {
620 } /* if (feof (infile)) */
623 *(pointer - 1) = ' ';
625 if (pointer == &storage[COMMENT_BUFFER_SIZE]) {
626 store_comment (storage);
628 } /* if (pointer == BUFFER_SIZE) */
631 if (pointer > storage) {
634 /* Get rid of the newline */
640 store_comment (storage);
644 if (c != '\n') /* To allow the line index to
645 increment correctly */
655 /* Load buffer a with the statement label */
657 /* a tab in columns 1-6 skips to column 7 */
659 for(p=a; p<aend && (c=getc(infile)) != '\n' && c!=EOF; )
662 /* The tab character translates into blank characters in the statement label */
675 /* By now we've read either a continuation character or the statement label
681 /* The next 'if' block handles lines that have fewer than 7 characters */
688 /* Blank out the buffer on lines which are not longer than 66 characters */
695 else { /* read body of line */
696 while( endcd<bend && (c=getc(infile)) != '\n' && c!=EOF )
701 /* Drop any extra characters on the input card; this usually means those after
706 while( (c=getc(infile)) != '\n')
717 /* The flow of control usually gets to this line (unless an earlier RETURN has
722 /* Fortran 77 specifies that a 0 in column 6 */
723 /* does not signify continuation */
725 if( !isspace(a[5]) && a[5]!='0') {
727 for(p = a; p < aend;)
728 if (*p++ == '!' && p != aend)
730 if (addftnsrc && stb) {
731 if (stbend > stb + 7) { /* otherwise forget col 1-6 */
732 /* kludge around funny p1gets behavior */
737 for(p = a; p < atend;)
740 if (endcd0 - b > stbend - stb) {
743 endcd0 = b + (stbend - stb);
745 for(p = b; p < endcd0;)
752 errstr("illegal continuation card (starts \"%.6s\")",a);
754 else if (!amp && strncmp(a," ",5)) {
756 errstr("labeled continuation line (starts \"%.6s\")",a);
761 for(p=a; p<atend; ++p)
765 bang(p, atend, aend, b, endcd);
768 for(p = b ; p<endcd ; ++p)
772 bang(a, a, a, p, endcd);
776 /* Skip over blank cards by reading the next one right away */
783 if (!laststb && stb0)
785 stb0 = stb = stbuf[nst];
786 *stb++ = '$'; /* kludge around funny p1gets behavior */
787 stbend = stb + sizeof(stbuf[0])-2;
788 for(p = a; p < atend;)
792 for(p = b; p < endcd0;)
798 /* Set nxtstno equal to the integer value of the statement label */
802 for(p = a ; p < bend ; ++p)
805 nxtstno = 10*nxtstno + (*p - '0');
806 else if (*p == '!') {
808 bang(p+1,atend,aend,b,endcd);
815 "nondigit in statement label field \"%.5s\"", a);
824 /* crunch -- deletes all space characters, folds the backslash chars and
825 Hollerith strings, quotes the Fortran strings */
830 register char *i, *j, *j0, *j1, *prvstr;
831 int k, ten, nh, nh0, quote;
833 /* i is the next input character to be looked at
834 j is the next output character */
836 new_dcl = needwkey = parlev = parseen = 0;
837 expcom = 0; /* exposed ','s */
838 expeql = 0; /* exposed equal signs */
842 for(i=sbuf ; i<=lastch ; ++i)
847 while(i >= linestart[k])
849 Fatal("too many continuations\n");
852 bang(sbuf,sbuf,sbuf,i+1,j0);
857 /* Keep everything in a quoted string */
859 if(*i=='\'' || *i=='"')
864 *j = MYQUOTE; /* special marker */
869 err("unbalanced quotes; closing quote supplied");
875 if(i<lastch && i[1]==quote) ++i;
877 else if(*i=='\\' && i<lastch && use_bs) {
879 *i = escapes[*(unsigned char *)i];
881 if (len + 2 < MAXTOKENLEN)
883 else if (len + 2 == MAXTOKENLEN)
885 ("String too long, truncating to %d chars", MAXTOKENLEN - 2);
893 else if( (*i=='h' || *i=='H') && j>prvstr) /* test for Hollerith strings */
896 if( ! isdigit(*j0)) goto copychar;
905 if( ! isdigit(*j0 ) ) break;
906 nh += ten * (*j0-'0');
909 /* a hollerith must be preceded by a punctuation mark.
910 '*' is possible only as repetition factor in a data statement
911 not, in particular, in character*2h
914 if( !(*j0=='*'&&sbuf[0]=='d') && *j0!='/'
915 && *j0!='(' && *j0!=',' && *j0!='=' && *j0!='.')
918 if(i+nh > lastch || nh + 2 > MAXTOKENLEN)
920 erri("%dH too big", nh);
922 if (nh > MAXTOKENLEN - 2)
923 nh = MAXTOKENLEN - 2;
926 j0[1] = MYQUOTE; /* special marker */
933 erri("escapes make %dH too big",
937 if(*i == '\\' && use_bs) {
940 *i = escapes[*(unsigned char *)i];
949 if(*i == '(') parseen = ++parlev;
950 else if(*i == ')') --parlev;
952 if(*i == '=') expeql = 1;
953 else if(*i == ',') expcom = 1;
954 copychar: /*not a string or space -- copy, shifting case if necessary */
955 if(shiftcase && isupper(*i))
971 err("unbalanced parentheses, statement skipped");
973 lastch = sbuf - 1; /* prevent double error msg */
976 if(nextch+2<=lastch && nextch[0]=='i' && nextch[1]=='f' && nextch[2]=='(')
978 /* assignment or if statement -- look at character after balancing paren */
980 for(i=nextch+3 ; i<=lastch; ++i)
983 while(*++i != MYQUOTE)
997 else if( isdigit(i[1]) )
1003 else if(expeql) /* may be an assignment */
1005 if(expcom && nextch<lastch &&
1006 nextch[0]=='d' && nextch[1]=='o')
1013 else if (parseen && nextch + 7 < lastch
1014 && nextch[2] != 'u' /* screen out "double..." early */
1015 && nextch[0] == 'd' && nextch[1] == 'o'
1016 && ((nextch[2] >= '0' && nextch[2] <= '9')
1018 || nextch[2] == 'w'))
1024 /* otherwise search for keyword */
1027 if(stkey==SGOTO && lastch>=nextch)
1030 else if(isalpha_(* USC nextch))
1041 register char *i, *j;
1042 register struct Keylist *pk, *pend;
1045 if(! isalpha_(* USC nextch) )
1047 k = letter(nextch[0]);
1048 if(pk = keystart[k])
1049 for(pend = keyend[k] ; pk<=pend ; ++pk )
1053 while(*++i==*++j && *i!='\0')
1055 if(*i=='\0' && j<=lastch+1)
1058 if(no66flag && pk->notinf66)
1059 errstr("Not a Fortran 66 keyword: %s",
1069 register struct Keylist *p;
1073 for(i = 0 ; i<26 ; ++i)
1076 for(p = keys ; p->keyname ; ++p) {
1077 j = letter(p->keyname[0]);
1078 if(keystart[j] == NULL)
1082 comstart['c'] = comstart['C'] = comstart['*'] = comstart['!'] = 1;
1083 s = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_";
1106 kind = "hexadecimal";
1121 err("bad bit identifier");
1124 for(p = token; *p; p++)
1125 if (hextoi(*p) >= radix) {
1126 errstr("invalid %s character", kind);
1132 /* gettok -- moves the right amount of text from nextch into the token
1133 buffer. token initially contains garbage (leftovers from the prev token) */
1138 int havdot, havexp, havdbl;
1140 struct Punctlist *pp;
1144 char *i, *j, *n1, *p;
1151 while(*nextch != MYQUOTE)
1155 /* allow octal, binary, hex constants of the form 'abc'x (etc.) */
1156 if (++nextch <= lastch && isalpha_(val = * USC nextch)) {
1158 return hexcheck(val);
1160 return (SHOLLERITH);
1169 for(pp=puncts; pp->punchar; ++pp)
1170 if(ch == pp->punchar) {
1172 if (++nextch <= lastch)
1175 if (*nextch == '/') {
1179 else if (new_dcl && parlev == 0)
1183 if (*nextch == '*') {
1189 if (*nextch == '=') {
1193 if (*nextch == '>') {
1199 if (*nextch == '=') {
1206 if (*nextch == '=') {
1211 NOEXT("Fortran 8x comparison operator");
1214 else if (ch == '/' && new_dcl && parlev == 0)
1226 if(nextch >= lastch) goto badchar;
1227 else if(isdigit(nextch[1])) goto numconst;
1229 for(pd=dots ; (j=pd->dotname) ; ++pd)
1231 for(i=nextch+1 ; i<=lastch ; ++i)
1233 else if(*i != '.') ++j;
1245 while(nextch<=lastch)
1246 if( isalnum_(* USC nextch) )
1254 && nextch <= lastch && *nextch == '(' /*)*/
1255 && !strcmp(token,"while"))
1258 if(inioctl && nextch<=lastch && *nextch=='=')
1263 if(toklen>8 && eqn(8,token,"function")
1264 && isalpha_(* USC (token+8)) &&
1265 nextch<lastch && nextch[0]=='(' &&
1266 (nextch[1]==')' || isalpha_(* USC (nextch+1))) )
1268 nextch -= (toklen - 8);
1275 sprintf(buff, toklen >= 60
1276 ? "name %.56s... too long, truncated to %.*s"
1277 : "name %s too long, truncated to %.*s",
1283 if(toklen==1 && *nextch==MYQUOTE) {
1286 for(p = token ; *nextch!=MYQUOTE ; )
1291 return hexcheck(val);
1298 /* Check for NAG's special hex constant */
1300 if (nextch[1] == '#'
1301 || nextch[2] == '#' && isdigit(nextch[1])) {
1303 radix = atoi (nextch);
1304 if (*++nextch != '#')
1306 if (radix != 2 && radix != 8 && radix != 16) {
1307 erri("invalid base %d for constant, defaulting to hex",
1311 if (++nextch > lastch)
1313 for (p = token; hextoi(*nextch) < radix;) {
1315 if (nextch > lastch)
1320 return (radix == 16) ? SHEXCON : ((radix == 8) ? SOCTCON :
1330 for(n1 = nextch ; nextch<=lastch ; ++nextch)
1334 else if(nextch+2<=lastch && isalpha_(* USC (nextch+1))
1335 && isalpha_(* USC (nextch+2)))
1338 else if( !intonly && (*nextch=='d' || *nextch=='e') )
1345 if(nextch[1]=='+' || nextch[1]=='-')
1347 if( ! isdigit(*++nextch) )
1350 havdbl = havexp = NO;
1354 nextch<=lastch && isdigit(* USC nextch);
1358 else if( ! isdigit(* USC nextch) )
1367 if(havdbl) return(SDCON);
1368 if(havdot || havexp) return(SRCON);
1371 sbuf[0] = *nextch++;
1375 /* Comment buffering code */
1384 if (nextcd == sbuf) {
1389 len = strlen(str) + 1;
1390 if (cbnext + len > cblast) {
1391 if (!cbcur || !(ncb = cbcur->next)) {
1392 ncb = (comment_buf *) Alloc(sizeof(comment_buf));
1394 cbcur->last = cbnext;
1405 cblast = cbnext + COMMENT_BUF_STORE;
1407 strcpy(cbnext, str);
1414 register char *s, *s1;
1415 register comment_buf *cb;
1416 if (cbnext == cbinit)
1418 cbcur->last = cbnext;
1419 for(cb = cbfirst;; cb = cb->next) {
1420 for(s = cb->buf; s < cb->last; s = s1) {
1421 /* compute s1 = new s value first, since */
1422 /* p1_comment may insert nulls into s */
1423 s1 = s + strlen(s) + 1;
1431 cblast = cbnext + COMMENT_BUF_STORE;
1437 register char *s, *se;
1447 if (*s == MYQUOTE) {
1452 errstr("unclassifiable statement (starts \"%s\")", sbuf);