/* * Copyright (c) 1980 Regents of the University of California. * All rights reserved. The Berkeley software License Agreement * specifies the terms and conditions for redistribution. */ #ifndef lint static char sccsid[] = "@(#)lex.c 5.3 (Berkeley) 1/7/86"; #endif not lint /* * lex.c * * Lexical scanner routines for the f77 compiler, pass 1, 4.2 BSD. * * University of Utah CS Dept modification history: * * $Log: lex.c,v $ * Revision 5.4 86/01/07 14:01:13 donn * Fix the scanning for character constants in gettok() so that it handles * the case when an error has occurred and there is no closing quote. * * Revision 5.3 85/11/25 00:24:06 donn * 4.3 beta * * Revision 5.2 85/08/10 04:45:41 donn * Jerry Berkman's changes to ifdef 66 code and handle -r8/double flag. * * Revision 5.1 85/08/10 03:48:20 donn * 4.3 alpha * * Revision 1.2 84/10/27 02:20:09 donn * Fixed bug where the input file and the name field of the include file * structure shared -- when the input file name was freed, the include file * name got stomped on, leading to peculiar error messages. * */ #include "defs.h" #include "tokdefs.h" # define BLANK ' ' # define MYQUOTE (2) # define SEOF 0 /* card types */ # define STEOF 1 # define STINITIAL 2 # define STCONTINUE 3 /* lex states */ #define NEWSTMT 1 #define FIRSTTOKEN 2 #define OTHERTOKEN 3 #define RETEOS 4 LOCAL int stkey; LOCAL int lastend = 1; ftnint yystno; flag intonly; LOCAL long int stno; LOCAL long int nxtstno; LOCAL int parlev; LOCAL int expcom; LOCAL int expeql; LOCAL char *nextch; LOCAL char *lastch; LOCAL char *nextcd = NULL; LOCAL char *endcd; LOCAL int prevlin; LOCAL int thislin; LOCAL int code; LOCAL int lexstate = NEWSTMT; LOCAL char s[1390]; LOCAL char *send = s+20*66; LOCAL int nincl = 0; LOCAL char *newname = NULL; struct Inclfile { struct Inclfile *inclnext; FILEP inclfp; char *inclname; int incllno; char *incllinp; int incllen; int inclcode; ftnint inclstno; } ; LOCAL struct Inclfile *inclp = NULL; LOCAL struct Keylist { char *keyname; int keyval; char notinf66; } ; LOCAL struct Punctlist { char punchar; int punval; }; LOCAL struct Fmtlist { char fmtchar; int fmtval; }; LOCAL struct Dotlist { char *dotname; int dotval; }; LOCAL struct Keylist *keystart[26], *keyend[26]; inilex(name) char *name; { nincl = 0; inclp = NULL; doinclude(name); lexstate = NEWSTMT; return(NO); } /* throw away the rest of the current line */ flline() { lexstate = RETEOS; } char *lexline(n) int *n; { *n = (lastch - nextch) + 1; return(nextch); } doinclude(name) char *name; { FILEP fp; struct Inclfile *t; char temp[100]; register char *lastslash, *s; if(inclp) { inclp->incllno = thislin; inclp->inclcode = code; inclp->inclstno = nxtstno; if(nextcd) inclp->incllinp = copyn(inclp->incllen = endcd-nextcd , nextcd); else inclp->incllinp = 0; } nextcd = NULL; if(++nincl >= MAXINCLUDES) fatal("includes nested too deep"); if(name[0] == '\0') fp = stdin; else if(name[0]=='/' || inclp==NULL) fp = fopen(name, "r"); else { lastslash = NULL; for(s = inclp->inclname ; *s ; ++s) if(*s == '/') lastslash = s; if(lastslash) { *lastslash = '\0'; sprintf(temp, "%s/%s", inclp->inclname, name); *lastslash = '/'; } else strcpy(temp, name); if( (fp = fopen(temp, "r")) == NULL ) { sprintf(temp, "/usr/include/%s", name); fp = fopen(temp, "r"); } if(fp) name = copys(temp); } if( fp ) { t = inclp; inclp = ALLOC(Inclfile); inclp->inclnext = t; prevlin = thislin = 0; inclp->inclname = name; infname = copys(name); infile = inclp->inclfp = fp; } else { fprintf(diagfile, "Cannot open file %s", name); done(1); } } LOCAL popinclude() { struct Inclfile *t; register char *p; register int k; if(infile != stdin) clf(&infile); free(infname); --nincl; t = inclp->inclnext; free(inclp->inclname); free( (charptr) inclp); inclp = t; if(inclp == NULL) return(NO); infile = inclp->inclfp; infname = copys(inclp->inclname); prevlin = thislin = inclp->incllno; code = inclp->inclcode; stno = nxtstno = inclp->inclstno; if(inclp->incllinp) { endcd = nextcd = s; k = inclp->incllen; p = inclp->incllinp; while(--k >= 0) *endcd++ = *p++; free( (charptr) (inclp->incllinp) ); } else nextcd = NULL; return(YES); } yylex() { static int tokno; switch(lexstate) { case NEWSTMT : /* need a new statement */ if(getcds() == STEOF) return(SEOF); lastend = stkey == SEND; crunch(); tokno = 0; lexstate = FIRSTTOKEN; yystno = stno; stno = nxtstno; toklen = 0; return(SLABEL); first: case FIRSTTOKEN : /* first step on a statement */ analyz(); lexstate = OTHERTOKEN; tokno = 1; return(stkey); case OTHERTOKEN : /* return next token */ if(nextch > lastch) goto reteos; ++tokno; if( (stkey==SLOGIF || stkey==SELSEIF) && parlev==0 && tokno>3) goto first; if(stkey==SASSIGN && tokno==3 && nextch s) { q = nextcd; p = s; while(q < endcd) *p++ = *q++; endcd = p; } for(nextcd = endcd ; nextcd+66<=send && (code = getcd(nextcd))==STCONTINUE ; nextcd = endcd ) ; nextch = s; lastch = nextcd - 1; if(nextcd >= send) nextcd = NULL; lineno = prevlin; prevlin = thislin; return(STINITIAL); } LOCAL getcd(b) register char *b; { register int c; register char *p, *bend; int speclin; static char a[6]; static char *aend = a+6; int num; top: endcd = b; bend = b+66; speclin = NO; if( (c = getc(infile)) == '&') { a[0] = BLANK; a[5] = 'x'; speclin = YES; bend = send; } else if(c=='c' || c=='C' || c=='*') { while( (c = getc(infile)) != '\n') if(c == EOF) return(STEOF); ++thislin; goto top; } else if(c == '#') { c = getc(infile); while (c == BLANK || c == '\t') c = getc(infile); num = 0; while (isdigit(c)) { num = 10*num + c - '0'; c = getc(infile); } thislin = num - 1; while (c == BLANK || c == '\t') c = getc(infile); if (c == '"') { char fname[1024]; int len = 0; c = getc(infile); while (c != '"' && c != '\n') { fname[len++] = c; c = getc(infile); } fname[len++] = '\0'; if (newname) free(newname); newname = (char *) ckalloc(len); strcpy(newname, fname); } while (c != '\n') if (c == EOF) return (STEOF); else c = getc(infile); goto top; } else if(c != EOF) { /* a tab in columns 1-6 skips to column 7 */ ungetc(c, infile); for(p=a; p lastch) { err("unbalanced quotes; closing quote supplied"); break; } if(*i == quote) if(iprvstr) /* test for Hollerith strings */ { if( ! isdigit(j[-1])) goto copychar; nh = j[-1] - '0'; ten = 10; j1 = prvstr - 1; if (j1j1; -- j0) { if( ! isdigit(*j0 ) ) break; nh += ten * (*j0-'0'); ten*=10; } if(j0 <= j1) goto copychar; /* a hollerith must be preceded by a punctuation mark. '*' is possible only as repetition factor in a data statement not, in particular, in character*2h */ if( !(*j0=='*'&&s[0]=='d') && *j0!='/' && *j0!='(' && *j0!=',' && *j0!='=' && *j0!='.') goto copychar; if(i+nh > lastch) { erri("%dH too big", nh); nh = lastch - i; } j0[1] = MYQUOTE; /* special marker */ j = j0 + 1; while(nh-- > 0) { if(*++i == '\\') switch(*++i) { case 't': *i = '\t'; break; case 'b': *i = '\b'; break; case 'n': *i = '\n'; break; case 'f': *i = '\f'; break; case '0': *i = '\0'; break; default: break; } *++j = *i; } j[1] = MYQUOTE; j+=2; prvstr = j; } else { if(*i == '(') ++parlev; else if(*i == ')') --parlev; else if(parlev == 0) if(*i == '=') expeql = 1; else if(*i == ',') expcom = 1; copychar: /*not a string or space -- copy, shifting case if necessary */ if(shiftcase && isupper(*i)) *j++ = tolower(*i); else *j++ = *i; } } lastch = j - 1; nextch = s; } LOCAL analyz() { register char *i; if(parlev != 0) { err("unbalanced parentheses, statement skipped"); stkey = SUNKNOWN; return; } if(nextch+2<=lastch && nextch[0]=='i' && nextch[1]=='f' && nextch[2]=='(') { /* assignment or if statement -- look at character after balancing paren */ parlev = 1; for(i=nextch+3 ; i<=lastch; ++i) if(*i == (MYQUOTE)) { while(*++i != MYQUOTE) ; } else if(*i == '(') ++parlev; else if(*i == ')') { if(--parlev == 0) break; } if(i >= lastch) stkey = SLOGIF; else if(i[1] == '=') stkey = SLET; else if( isdigit(i[1]) ) stkey = SARITHIF; else stkey = SLOGIF; if(stkey != SLET) nextch += 2; } else if(expeql) /* may be an assignment */ { if(expcom && nextch=nextch) if(nextch[0]=='(') stkey = SCOMPGOTO; else if(isalpha(nextch[0])) stkey = SASGOTO; } parlev = 0; } LOCAL getkwd() { register char *i, *j; register struct Keylist *pk, *pend; int k; if(! isalpha(nextch[0]) ) return(SUNKNOWN); k = nextch[0] - 'a'; if(pk = keystart[k]) for(pend = keyend[k] ; pk<=pend ; ++pk ) { i = pk->keyname; j = nextch; while(*++i==*++j && *i!='\0') ; if(*i=='\0' && j<=lastch+1) { nextch = j; #ifdef ONLY66 if(no66flag && pk->notinf66) errstr("Not a Fortran 66 keyword: %s", pk->keyname); #endif return(pk->keyval); } } return(SUNKNOWN); } initkey() { extern struct Keylist keys[]; register struct Keylist *p; register int i,j; for(i = 0 ; i<26 ; ++i) keystart[i] = NULL; for(p = keys ; p->keyname ; ++p) { j = p->keyname[0] - 'a'; if(keystart[j] == NULL) keystart[j] = p; keyend[j] = p; } } LOCAL gettok() { int havdot, havexp, havdbl; int radix, val; extern struct Punctlist puncts[]; struct Punctlist *pp; extern struct Fmtlist fmts[]; extern struct Dotlist dots[]; struct Dotlist *pd; char *i, *j, *n1, *p; if(*nextch == (MYQUOTE)) { ++nextch; p = token; while(nextch <= lastch && *nextch != MYQUOTE) *p++ = *nextch++; ++nextch; toklen = p - token; *p = '\0'; return (SHOLLERITH); } /* if(stkey == SFORMAT) { for(pf = fmts; pf->fmtchar; ++pf) { if(*nextch == pf->fmtchar) { ++nextch; if(pf->fmtval == SLPAR) ++parlev; else if(pf->fmtval == SRPAR) --parlev; return(pf->fmtval); } } if( isdigit(*nextch) ) { p = token; *p++ = *nextch++; while(nextch<=lastch && isdigit(*nextch) ) *p++ = *nextch++; toklen = p - token; *p = '\0'; if(nextch<=lastch && *nextch=='p') { ++nextch; return(SSCALE); } else return(SICON); } if( isalpha(*nextch) ) { p = token; *p++ = *nextch++; while(nextch<=lastch && (*nextch=='.' || isdigit(*nextch) || isalpha(*nextch) )) *p++ = *nextch++; toklen = p - token; *p = '\0'; return(SFIELD); } goto badchar; } /* Not a format statement */ if(needkwd) { needkwd = 0; return( getkwd() ); } for(pp=puncts; pp->punchar; ++pp) if(*nextch == pp->punchar) { if( (*nextch=='*' || *nextch=='/') && nextchpunval; if(val==SLPAR) ++parlev; else if(val==SRPAR) --parlev; ++nextch; } return(val); } if(*nextch == '.') if(nextch >= lastch) goto badchar; else if(isdigit(nextch[1])) goto numconst; else { for(pd=dots ; (j=pd->dotname) ; ++pd) { for(i=nextch+1 ; i<=lastch ; ++i) if(*i != *j) break; else if(*i != '.') ++j; else { nextch = i+1; return(pd->dotval); } } goto badchar; } if( isalpha(*nextch) ) { p = token; *p++ = *nextch++; while(nextch<=lastch) if( isalpha(*nextch) || isdigit(*nextch) ) *p++ = *nextch++; else break; toklen = p - token; *p = '\0'; if(inioctl && nextch<=lastch && *nextch=='=') { ++nextch; return(SNAMEEQ); } if(toklen>8 && eqn(8,token,"function") && isalpha(token[8]) && nextch VL) { char buff[30]; sprintf(buff, "name %s too long, truncated to %d", token, VL); err(buff); toklen = VL; token[VL] = '\0'; } if(toklen==1 && *nextch==MYQUOTE) { switch(token[0]) { case 'z': case 'Z': case 'x': case 'X': radix = 16; break; case 'o': case 'O': radix = 8; break; case 'b': case 'B': radix = 2; break; default: err("bad bit identifier"); return(SNAME); } ++nextch; for(p = token ; *nextch!=MYQUOTE ; ) if ( *nextch == BLANK || *nextch == '\t') nextch++; else { if (isupper(*nextch)) *nextch = tolower(*nextch); if (hextoi(*p++ = *nextch++) >= radix) { err("invalid binary character"); break; } } ++nextch; toklen = p - token; return( radix==16 ? SHEXCON : (radix==8 ? SOCTCON : SBITCON) ); } return(SNAME); } if( ! isdigit(*nextch) ) goto badchar; numconst: havdot = NO; havexp = NO; havdbl = NO; for(n1 = nextch ; nextch<=lastch ; ++nextch) { if(*nextch == '.') if(havdot) break; else if(nextch+2<=lastch && isalpha(nextch[1]) && isalpha(nextch[2])) break; else havdot = YES; else if( !intonly && (*nextch=='d' || *nextch=='e') ) { p = nextch; havexp = YES; if(*nextch == 'd') havdbl = YES; if(nextch= lastch) || ! isdigit(*++nextch) ) { nextch = p; havdbl = havexp = NO; break; } for(++nextch ; nextch<=lastch && isdigit(*nextch); ++nextch); break; } else if( ! isdigit(*nextch) ) break; } p = token; i = n1; while(i < nextch) *p++ = *i++; toklen = p - token; *p = '\0'; if(havdbl) return(SDCON); if(havdot || havexp) return( dblflag ? SDCON : SRCON); return(SICON); badchar: s[0] = *nextch++; return(SUNKNOWN); } /* KEYWORD AND SPECIAL CHARACTER TABLES */ struct Punctlist puncts[ ] = { '(', SLPAR, ')', SRPAR, '=', SEQUALS, ',', SCOMMA, '+', SPLUS, '-', SMINUS, '*', SSTAR, '/', SSLASH, '$', SCURRENCY, ':', SCOLON, 0, 0 } ; /* LOCAL struct Fmtlist fmts[ ] = { '(', SLPAR, ')', SRPAR, '/', SSLASH, ',', SCOMMA, '-', SMINUS, ':', SCOLON, 0, 0 } ; */ LOCAL struct Dotlist dots[ ] = { "and.", SAND, "or.", SOR, "not.", SNOT, "true.", STRUE, "false.", SFALSE, "eq.", SEQ, "ne.", SNE, "lt.", SLT, "le.", SLE, "gt.", SGT, "ge.", SGE, "neqv.", SNEQV, "eqv.", SEQV, 0, 0 } ; LOCAL struct Keylist keys[ ] = { { "assign", SASSIGN }, { "automatic", SAUTOMATIC, YES }, { "backspace", SBACKSPACE }, { "blockdata", SBLOCK }, { "call", SCALL }, { "character", SCHARACTER, YES }, { "close", SCLOSE, YES }, { "common", SCOMMON }, { "complex", SCOMPLEX }, { "continue", SCONTINUE }, { "data", SDATA }, { "dimension", SDIMENSION }, { "doubleprecision", SDOUBLE }, { "doublecomplex", SDCOMPLEX, YES }, { "elseif", SELSEIF, YES }, { "else", SELSE, YES }, { "endfile", SENDFILE }, { "endif", SENDIF, YES }, { "end", SEND }, { "entry", SENTRY, YES }, { "equivalence", SEQUIV }, { "external", SEXTERNAL }, { "format", SFORMAT }, { "function", SFUNCTION }, { "goto", SGOTO }, { "implicit", SIMPLICIT, YES }, { "include", SINCLUDE, YES }, { "inquire", SINQUIRE, YES }, { "intrinsic", SINTRINSIC, YES }, { "integer", SINTEGER }, { "logical", SLOGICAL }, #ifdef NAMELIST { "namelist", SNAMELIST, YES }, #endif { "none", SUNDEFINED, YES }, { "open", SOPEN, YES }, { "parameter", SPARAM, YES }, { "pause", SPAUSE }, { "print", SPRINT }, { "program", SPROGRAM, YES }, { "punch", SPUNCH, YES }, { "read", SREAD }, { "real", SREAL }, { "return", SRETURN }, { "rewind", SREWIND }, { "save", SSAVE, YES }, { "static", SSTATIC, YES }, { "stop", SSTOP }, { "subroutine", SSUBROUTINE }, { "then", STHEN, YES }, { "undefined", SUNDEFINED, YES }, { "write", SWRITE }, { 0, 0 } };