1453 lines
		
	
	
	
		
			29 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			1453 lines
		
	
	
	
		
			29 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /****************************************************************
 | |
| Copyright 1990 by AT&T Bell Laboratories and Bellcore.
 | |
| 
 | |
| Permission to use, copy, modify, and distribute this software
 | |
| and its documentation for any purpose and without fee is hereby
 | |
| granted, provided that the above copyright notice appear in all
 | |
| copies and that both that the copyright notice and this
 | |
| permission notice and warranty disclaimer appear in supporting
 | |
| documentation, and that the names of AT&T Bell Laboratories or
 | |
| Bellcore or any of their entities not be used in advertising or
 | |
| publicity pertaining to distribution of the software without
 | |
| specific, written prior permission.
 | |
| 
 | |
| AT&T and Bellcore disclaim all warranties with regard to this
 | |
| software, including all implied warranties of merchantability
 | |
| and fitness.  In no event shall AT&T or Bellcore be liable for
 | |
| any special, indirect or consequential damages or any damages
 | |
| whatsoever resulting from loss of use, data or profits, whether
 | |
| in an action of contract, negligence or other tortious action,
 | |
| arising out of or in connection with the use or performance of
 | |
| this software.
 | |
| ****************************************************************/
 | |
| 
 | |
| #include "defs.h"
 | |
| #include "tokdefs.h"
 | |
| #include "p1defs.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;	/* Type of the current statement (DO, END, IF, etc) */
 | |
| extern char token[];	/* holds the actual token text */
 | |
| static int needwkey;
 | |
| ftnint yystno;
 | |
| flag intonly;
 | |
| extern int new_dcl;
 | |
| LOCAL long int stno;
 | |
| LOCAL long int nxtstno;	/* Statement label */
 | |
| LOCAL int parlev;	/* Parentheses level */
 | |
| LOCAL int parseen;
 | |
| LOCAL int expcom;
 | |
| LOCAL int expeql;
 | |
| LOCAL char *nextch;
 | |
| LOCAL char *lastch;
 | |
| LOCAL char *nextcd 	= NULL;
 | |
| LOCAL char *endcd;
 | |
| LOCAL long prevlin;
 | |
| LOCAL long thislin;
 | |
| LOCAL int code;		/* Card type; INITIAL, CONTINUE or EOF */
 | |
| LOCAL int lexstate	= NEWSTMT;
 | |
| LOCAL char sbuf[1390];	/* Main buffer for Fortran source input.  The number
 | |
| 			   comes from lines of at most 66 characters, with at
 | |
| 			   most 20 continuation cards (or something); this is
 | |
| 			   part of the defn of the standard */
 | |
| LOCAL char *send	= sbuf+20*66;
 | |
| LOCAL int nincl	= 0;	/* Current number of include files */
 | |
| LOCAL long firstline;
 | |
| LOCAL char *laststb, *stb0;
 | |
| extern int addftnsrc;
 | |
| #define CONTMAX 100	/* max continuation lines for ! processing */
 | |
| char *linestart[CONTMAX];
 | |
| LOCAL int ncont;
 | |
| LOCAL char comstart[Table_size];
 | |
| #define USC (unsigned char *)
 | |
| 
 | |
| static char anum_buf[Table_size];
 | |
| #define isalnum_(x) anum_buf[x]
 | |
| #define isalpha_(x) (anum_buf[x] == 1)
 | |
| 
 | |
| #define COMMENT_BUF_STORE 4088
 | |
| 
 | |
| typedef struct comment_buf {
 | |
| 	struct comment_buf *next;
 | |
| 	char *last;
 | |
| 	char buf[COMMENT_BUF_STORE];
 | |
| 	} comment_buf;
 | |
| static comment_buf *cbfirst, *cbcur;
 | |
| static char *cbinit, *cbnext, *cblast;
 | |
| static void flush_comments();
 | |
| extern flag use_bs;
 | |
| 
 | |
| 
 | |
| /* Comment buffering data
 | |
| 
 | |
| 	Comments are kept in a list until the statement before them has
 | |
|    been parsed.  This list is implemented with the above comment_buf
 | |
|    structure and the pointers cbnext and cblast.
 | |
| 
 | |
| 	The comments are stored with terminating NULL, and no other
 | |
|    intervening space.  The last few bytes of each block are likely to
 | |
|    remain unused.
 | |
| */
 | |
| 
 | |
| /* struct Inclfile   holds the state information for each include file */
 | |
| struct Inclfile
 | |
| {
 | |
| 	struct Inclfile *inclnext;
 | |
| 	FILEP inclfp;
 | |
| 	char *inclname;
 | |
| 	int incllno;
 | |
| 	char *incllinp;
 | |
| 	int incllen;
 | |
| 	int inclcode;
 | |
| 	ftnint inclstno;
 | |
| };
 | |
| 
 | |
| LOCAL struct Inclfile *inclp	=  NULL;
 | |
| struct Keylist {
 | |
| 	char *keyname;
 | |
| 	int keyval;
 | |
| 	char notinf66;
 | |
| };
 | |
| struct Punctlist {
 | |
| 	char punchar;
 | |
| 	int punval;
 | |
| };
 | |
| struct Fmtlist {
 | |
| 	char fmtchar;
 | |
| 	int fmtval;
 | |
| };
 | |
| struct Dotlist {
 | |
| 	char *dotname;
 | |
| 	int dotval;
 | |
| 	};
 | |
| LOCAL struct Keylist *keystart[26], *keyend[26];
 | |
| 
 | |
| /* KEYWORD AND SPECIAL CHARACTER TABLES
 | |
| */
 | |
| 
 | |
| static struct Punctlist puncts[ ] =
 | |
| {
 | |
| 	'(', SLPAR,
 | |
| 	')', SRPAR,
 | |
| 	'=', SEQUALS,
 | |
| 	',', SCOMMA,
 | |
| 	'+', SPLUS,
 | |
| 	'-', SMINUS,
 | |
| 	'*', SSTAR,
 | |
| 	'/', SSLASH,
 | |
| 	'$', SCURRENCY,
 | |
| 	':', SCOLON,
 | |
| 	'<', SLT,
 | |
| 	'>', SGT,
 | |
| 	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  },
 | |
| 	{ "enddo", SENDDO, 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  },
 | |
| 	{ "namelist", SNAMELIST, YES },
 | |
| 	{ "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  },
 | |
| 	{ "while", SWHILE, YES  },
 | |
| 	{ "write",  SWRITE  },
 | |
| 	{ 0, 0 }
 | |
| };
 | |
| 
 | |
| LOCAL void analyz(), crunch(), store_comment();
 | |
| LOCAL int getcd(), getcds(), getkwd(), gettok();
 | |
| LOCAL char *stbuf[3];
 | |
| 
 | |
| inilex(name)
 | |
| char *name;
 | |
| {
 | |
| 	stbuf[0] = Alloc(3*P1_STMTBUFSIZE);
 | |
| 	stbuf[1] = stbuf[0] + P1_STMTBUFSIZE;
 | |
| 	stbuf[2] = stbuf[1] + P1_STMTBUFSIZE;
 | |
| 	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;
 | |
| 
 | |
| 	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
 | |
| 		fp = fopen(name, textread);
 | |
| 	if (fp)
 | |
| 	{
 | |
| 		t = inclp;
 | |
| 		inclp = ALLOC(Inclfile);
 | |
| 		inclp->inclnext = t;
 | |
| 		prevlin = thislin = 0;
 | |
| 		infname = inclp->inclname = name;
 | |
| 		infile = inclp->inclfp = fp;
 | |
| 	}
 | |
| 	else
 | |
| 	{
 | |
| 		fprintf(diagfile, "Cannot open file %s\n", name);
 | |
| 		done(1);
 | |
| 	}
 | |
| }
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
| LOCAL popinclude()
 | |
| {
 | |
| 	struct Inclfile *t;
 | |
| 	register char *p;
 | |
| 	register int k;
 | |
| 
 | |
| 	if(infile != stdin)
 | |
| 		clf(&infile, infname, 1);	/* Close the input file */
 | |
| 	free(infname);
 | |
| 
 | |
| 	--nincl;
 | |
| 	t = inclp->inclnext;
 | |
| 	free( (charptr) inclp);
 | |
| 	inclp = t;
 | |
| 	if(inclp == NULL) {
 | |
| 		infname = 0;
 | |
| 		return(NO);
 | |
| 		}
 | |
| 
 | |
| 	infile = inclp->inclfp;
 | |
| 	infname = inclp->inclname;
 | |
| 	prevlin = thislin = inclp->incllno;
 | |
| 	code = inclp->inclcode;
 | |
| 	stno = nxtstno = inclp->inclstno;
 | |
| 	if(inclp->incllinp)
 | |
| 	{
 | |
| 		endcd = nextcd = sbuf;
 | |
| 		k = inclp->incllen;
 | |
| 		p = inclp->incllinp;
 | |
| 		while(--k >= 0)
 | |
| 			*endcd++ = *p++;
 | |
| 		free( (charptr) (inclp->incllinp) );
 | |
| 	}
 | |
| 	else
 | |
| 		nextcd = NULL;
 | |
| 	return(YES);
 | |
| }
 | |
| 
 | |
|  static void
 | |
| putlineno()
 | |
| {
 | |
| 	static long lastline;
 | |
| 	static char *lastfile = "??", *lastfile0 = "?";
 | |
| 	static char fbuf[P1_FILENAME_MAX];
 | |
| 	extern int gflag;
 | |
| 	register char *s0, *s1;
 | |
| 
 | |
| 	if (gflag) {
 | |
| 		if (lastline) {
 | |
| 			if (lastfile != lastfile0) {
 | |
| 				p1puts(P1_FILENAME, fbuf);
 | |
| 				lastfile0 = lastfile;
 | |
| 				}
 | |
| 			p1_line_number(lastline);
 | |
| 			}
 | |
| 		lastline = firstline;
 | |
| 		if (lastfile != infname)
 | |
| 			if (lastfile = infname) {
 | |
| 				strncpy(fbuf, lastfile, sizeof(fbuf));
 | |
| 				fbuf[sizeof(fbuf)-1] = 0;
 | |
| 				}
 | |
| 			else
 | |
| 				fbuf[0] = 0;
 | |
| 		}
 | |
| 	if (addftnsrc) {
 | |
| 		if (laststb && *laststb) {
 | |
| 			for(s1 = laststb; *s1; s1++) {
 | |
| 				for(s0 = s1; *s1 != '\n'; s1++)
 | |
| 					if (*s1 == '*' && s1[1] == '/')
 | |
| 						*s1 = '+';
 | |
| 				*s1 = 0;
 | |
| 				p1puts(P1_FORTRAN, s0);
 | |
| 				}
 | |
| 			*laststb = 0;	/* prevent trouble after EOF */
 | |
| 			}
 | |
| 		laststb = stb0;
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 
 | |
| yylex()
 | |
| {
 | |
| 	static int  tokno;
 | |
| 	int retval;
 | |
| 
 | |
| 	switch(lexstate)
 | |
| 	{
 | |
| 	case NEWSTMT :	/* need a new statement */
 | |
| 		retval = getcds();
 | |
| 		putlineno();
 | |
| 		if(retval == STEOF) {
 | |
| 			retval = SEOF;
 | |
| 			break;
 | |
| 		} /* if getcds() == STEOF */
 | |
| 		crunch();
 | |
| 		tokno = 0;
 | |
| 		lexstate = FIRSTTOKEN;
 | |
| 		yystno = stno;
 | |
| 		stno = nxtstno;
 | |
| 		toklen = 0;
 | |
| 		retval = SLABEL;
 | |
| 		break;
 | |
| 
 | |
| first:
 | |
| 	case FIRSTTOKEN :	/* first step on a statement */
 | |
| 		analyz();
 | |
| 		lexstate = OTHERTOKEN;
 | |
| 		tokno = 1;
 | |
| 		retval = stkey;
 | |
| 		break;
 | |
| 
 | |
| 	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<lastch &&
 | |
| 		    nextch[0]=='t' && nextch[1]=='o')
 | |
| 		{
 | |
| 			nextch+=2;
 | |
| 			retval = STO;
 | |
| 			break;
 | |
| 		}
 | |
| 		retval = gettok();
 | |
| 		break;
 | |
| 
 | |
| reteos:
 | |
| 	case RETEOS:
 | |
| 		lexstate = NEWSTMT;
 | |
| 		retval = SEOS;
 | |
| 		break;
 | |
| 	default:
 | |
| 		fatali("impossible lexstate %d", lexstate);
 | |
| 		break;
 | |
| 	}
 | |
| 
 | |
| 	if (retval == SEOF)
 | |
| 	    flush_comments ();
 | |
| 
 | |
| 	return retval;
 | |
| }
 | |
| 
 | |
| /* Get Cards.
 | |
| 
 | |
|    Returns STEOF or STINITIAL, never STCONTINUE.  Any continuation cards get
 | |
| merged into one long card (hence the size of the buffer named   sbuf)   */
 | |
| 
 | |
|  LOCAL int
 | |
| getcds()
 | |
| {
 | |
| 	register char *p, *q;
 | |
| 
 | |
| 	flush_comments ();
 | |
| top:
 | |
| 	if(nextcd == NULL)
 | |
| 	{
 | |
| 		code = getcd( nextcd = sbuf, 1 );
 | |
| 		stno = nxtstno;
 | |
| 		prevlin = thislin;
 | |
| 	}
 | |
| 	if(code == STEOF)
 | |
| 		if( popinclude() )
 | |
| 			goto top;
 | |
| 		else
 | |
| 			return(STEOF);
 | |
| 
 | |
| 	if(code == STCONTINUE)
 | |
| 	{
 | |
| 		lineno = thislin;
 | |
| 		nextcd = NULL;
 | |
| 		goto top;
 | |
| 	}
 | |
| 
 | |
| /* Get rid of unused space at the head of the buffer */
 | |
| 
 | |
| 	if(nextcd > sbuf)
 | |
| 	{
 | |
| 		q = nextcd;
 | |
| 		p = sbuf;
 | |
| 		while(q < endcd)
 | |
| 			*p++ = *q++;
 | |
| 		endcd = p;
 | |
| 	}
 | |
| 
 | |
| /* Be aware that the input (i.e. the string at the address   nextcd)   is NOT
 | |
|    NULL-terminated */
 | |
| 
 | |
| /* This loop merges all continuations into one long statement, AND puts the next
 | |
|    card to be read at the end of the buffer (i.e. it stores the look-ahead card
 | |
|    when there's room) */
 | |
| 
 | |
| 	ncont = 0;
 | |
| 	do {
 | |
| 		nextcd = endcd;
 | |
| 		if (ncont < CONTMAX)
 | |
| 			linestart[ncont++] = nextcd;
 | |
| 		}
 | |
| 		while(nextcd+66<=send && (code = getcd(nextcd,0))==STCONTINUE);
 | |
| 	nextch = sbuf;
 | |
| 	lastch = nextcd - 1;
 | |
| 
 | |
| /* Handle buffer overflow by zeroing the 'next' pointer   (nextcd)   so that
 | |
|    the top of this function will initialize it next time it is called */
 | |
| 
 | |
| 	if(nextcd >= send)
 | |
| 		nextcd = NULL;
 | |
| 	lineno = prevlin;
 | |
| 	prevlin = thislin;
 | |
| 	return(STINITIAL);
 | |
| }
 | |
| 
 | |
|  static void
 | |
| bang(a,b,c,d,e)		/* save ! comments */
 | |
|  char *a, *b, *c;
 | |
|  register char *d, *e;
 | |
| {
 | |
| 	char buf[COMMENT_BUFFER_SIZE + 1];
 | |
| 	register char *p, *pe;
 | |
| 
 | |
| 	p = buf;
 | |
| 	pe = buf + COMMENT_BUFFER_SIZE;
 | |
| 	*pe = 0;
 | |
| 	while(a < b)
 | |
| 		if (!(*p++ = *a++))
 | |
| 			p[-1] = 0;
 | |
| 	if (b < c)
 | |
| 		*p++ = '\t';
 | |
| 	while(d < e) {
 | |
| 		if (!(*p++ = *d++))
 | |
| 			p[-1] = ' ';
 | |
| 		if (p == pe) {
 | |
| 			store_comment(buf);
 | |
| 			p = buf;
 | |
| 			}
 | |
| 		}
 | |
| 	if (p > buf) {
 | |
| 		while(--p >= buf && *p == ' ');
 | |
| 		p[1] = 0;
 | |
| 		store_comment(buf);
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 
 | |
| /* getcd - Get next input card
 | |
| 
 | |
| 	This function reads the next input card from global file pointer   infile.
 | |
| It assumes that   b   points to currently empty storage somewhere in  sbuf  */
 | |
| 
 | |
|  LOCAL int
 | |
| getcd(b, nocont)
 | |
|  register char *b;
 | |
| {
 | |
| 	register int c;
 | |
| 	register char *p, *bend;
 | |
| 	int speclin;		/* Special line - true when the line is allowed
 | |
| 				   to have more than 66 characters (e.g. the
 | |
| 				   "&" shorthand for continuation, use of a "\t"
 | |
| 				   to skip part of the label columns) */
 | |
| 	static char a[6];	/* Statement label buffer */
 | |
| 	static char *aend	= a+6;
 | |
| 	static char *stb, *stbend;
 | |
| 	static int nst;
 | |
| 	char *atend, *endcd0;
 | |
| 	int amp;
 | |
| 	char storage[COMMENT_BUFFER_SIZE + 1];
 | |
| 	char *pointer;
 | |
| 
 | |
| top:
 | |
| 	endcd = b;
 | |
| 	bend = b+66;
 | |
| 	amp = speclin = NO;
 | |
| 	atend = aend;
 | |
| 
 | |
| /* Handle the continuation shorthand of "&" in the first column, which stands
 | |
|    for "     x" */
 | |
| 
 | |
| 	if( (c = getc(infile)) == '&')
 | |
| 	{
 | |
| 		a[0] = c;
 | |
| 		a[1] = 0;
 | |
| 		a[5] = 'x';
 | |
| 		amp = speclin = YES;
 | |
| 		bend = send;
 | |
| 		p = aend;
 | |
| 	}
 | |
| 
 | |
| /* Handle the Comment cards (a 'C', 'c', '*', or '!' in the first column). */
 | |
| 
 | |
| 	else if(comstart[c & 0xfff])
 | |
| 	{
 | |
| 		if (feof (infile))
 | |
| 		    return STEOF;
 | |
| 
 | |
| 		storage[COMMENT_BUFFER_SIZE] = c = '\0';
 | |
| 		pointer = storage;
 | |
| 		while( !feof (infile) && (*pointer++ = c = getc(infile)) != '\n') {
 | |
| 
 | |
| /* Handle obscure end of file conditions on many machines */
 | |
| 
 | |
| 			if (feof (infile) && (c == '\377' || c == EOF)) {
 | |
| 			    pointer--;
 | |
| 			    break;
 | |
| 			} /* if (feof (infile)) */
 | |
| 
 | |
| 			if (c == '\0')
 | |
| 				*(pointer - 1) = ' ';
 | |
| 
 | |
| 			if (pointer == &storage[COMMENT_BUFFER_SIZE]) {
 | |
| 				store_comment (storage);
 | |
| 				pointer = storage;
 | |
| 			} /* if (pointer == BUFFER_SIZE) */
 | |
| 		} /* while */
 | |
| 
 | |
| 		if (pointer > storage) {
 | |
| 		    if (c == '\n')
 | |
| 
 | |
| /* Get rid of the newline */
 | |
| 
 | |
| 			pointer[-1] = 0;
 | |
| 		    else
 | |
| 			*pointer = 0;
 | |
| 
 | |
| 		    store_comment (storage);
 | |
| 		} /* if */
 | |
| 
 | |
| 		if (feof (infile))
 | |
| 		    if (c != '\n')	/* To allow the line index to
 | |
| 					   increment correctly */
 | |
| 			return STEOF;
 | |
| 
 | |
| 		++thislin;
 | |
| 		goto top;
 | |
| 	}
 | |
| 
 | |
| 	else if(c != EOF)
 | |
| 	{
 | |
| 
 | |
| /* Load buffer   a   with the statement label */
 | |
| 
 | |
| 		/* a tab in columns 1-6 skips to column 7 */
 | |
| 		ungetc(c, infile);
 | |
| 		for(p=a; p<aend && (c=getc(infile)) != '\n' && c!=EOF; )
 | |
| 			if(c == '\t')
 | |
| 
 | |
| /* The tab character translates into blank characters in the statement label */
 | |
| 
 | |
| 			{
 | |
| 				atend = p;
 | |
| 				while(p < aend)
 | |
| 					*p++ = BLANK;
 | |
| 				speclin = YES;
 | |
| 				bend = send;
 | |
| 			}
 | |
| 			else
 | |
| 				*p++ = c;
 | |
| 	}
 | |
| 
 | |
| /* By now we've read either a continuation character or the statement label
 | |
|    field */
 | |
| 
 | |
| 	if(c == EOF)
 | |
| 		return(STEOF);
 | |
| 
 | |
| /* The next 'if' block handles lines that have fewer than 7 characters */
 | |
| 
 | |
| 	if(c == '\n')
 | |
| 	{
 | |
| 		while(p < aend)
 | |
| 			*p++ = BLANK;
 | |
| 
 | |
| /* Blank out the buffer on lines which are not longer than 66 characters */
 | |
| 
 | |
| 		endcd0 = endcd;
 | |
| 		if( ! speclin )
 | |
| 			while(endcd < bend)
 | |
| 				*endcd++ = BLANK;
 | |
| 	}
 | |
| 	else	{	/* read body of line */
 | |
| 		while( endcd<bend && (c=getc(infile)) != '\n' && c!=EOF )
 | |
| 			*endcd++ = c;
 | |
| 		if(c == EOF)
 | |
| 			return(STEOF);
 | |
| 
 | |
| /* Drop any extra characters on the input card; this usually means those after
 | |
|    column 72 */
 | |
| 
 | |
| 		if(c != '\n')
 | |
| 		{
 | |
| 			while( (c=getc(infile)) != '\n')
 | |
| 				if(c == EOF)
 | |
| 					return(STEOF);
 | |
| 		}
 | |
| 
 | |
| 		endcd0 = endcd;
 | |
| 		if( ! speclin )
 | |
| 			while(endcd < bend)
 | |
| 				*endcd++ = BLANK;
 | |
| 	}
 | |
| 
 | |
| /* The flow of control usually gets to this line (unless an earlier RETURN has
 | |
|    been taken) */
 | |
| 
 | |
| 	++thislin;
 | |
| 
 | |
| 	/* Fortran 77 specifies that a 0 in column 6 */
 | |
| 	/* does not signify continuation */
 | |
| 
 | |
| 	if( !isspace(a[5]) && a[5]!='0') {
 | |
| 		if (!amp)
 | |
| 			for(p = a; p < aend;)
 | |
| 				if (*p++ == '!' && p != aend)
 | |
| 					goto initcheck;
 | |
| 		if (addftnsrc && stb) {
 | |
| 			if (stbend > stb + 7) { /* otherwise forget col 1-6 */
 | |
| 				/* kludge around funny p1gets behavior */
 | |
| 				*stb++ = '$';
 | |
| 				if (amp)
 | |
| 					*stb++ = '&';
 | |
| 				else
 | |
| 					for(p = a; p < atend;)
 | |
| 						*stb++ = *p++;
 | |
| 				}
 | |
| 			if (endcd0 - b > stbend - stb) {
 | |
| 				if (stb > stbend)
 | |
| 					stb = stbend;
 | |
| 				endcd0 = b + (stbend - stb);
 | |
| 				}
 | |
| 			for(p = b; p < endcd0;)
 | |
| 				*stb++ = *p++;
 | |
| 			*stb++ = '\n';
 | |
| 			*stb = 0;
 | |
| 			}
 | |
| 		if (nocont) {
 | |
| 			lineno = thislin;
 | |
| 			errstr("illegal continuation card (starts \"%.6s\")",a);
 | |
| 			}
 | |
| 		else if (!amp && strncmp(a,"     ",5)) {
 | |
| 			lineno = thislin;
 | |
| 			errstr("labeled continuation line (starts \"%.6s\")",a);
 | |
| 			}
 | |
| 		return(STCONTINUE);
 | |
| 		}
 | |
| initcheck:
 | |
| 	for(p=a; p<atend; ++p)
 | |
| 		if( !isspace(*p) ) {
 | |
| 			if (*p++ != '!')
 | |
| 				goto initline;
 | |
| 			bang(p, atend, aend, b, endcd);
 | |
| 			goto top;
 | |
| 			}
 | |
| 	for(p = b ; p<endcd ; ++p)
 | |
| 		if( !isspace(*p) ) {
 | |
| 			if (*p++ != '!')
 | |
| 				goto initline;
 | |
| 			bang(a, a, a, p, endcd);
 | |
| 			goto top;
 | |
| 			}
 | |
| 
 | |
| /* Skip over blank cards by reading the next one right away */
 | |
| 
 | |
| 	goto top;
 | |
| 
 | |
| initline:
 | |
| 	if (addftnsrc) {
 | |
| 		nst = (nst+1)%3;
 | |
| 		if (!laststb && stb0)
 | |
| 			laststb = stb0;
 | |
| 		stb0 = stb = stbuf[nst];
 | |
| 		*stb++ = '$';	/* kludge around funny p1gets behavior */
 | |
| 		stbend = stb + sizeof(stbuf[0])-2;
 | |
| 		for(p = a; p < atend;)
 | |
| 			*stb++ = *p++;
 | |
| 		if (atend < aend)
 | |
| 			*stb++ = '\t';
 | |
| 		for(p = b; p < endcd0;)
 | |
| 			*stb++ = *p++;
 | |
| 		*stb++ = '\n';
 | |
| 		*stb = 0;
 | |
| 		}
 | |
| 
 | |
| /* Set   nxtstno   equal to the integer value of the statement label */
 | |
| 
 | |
| 	nxtstno = 0;
 | |
| 	bend = a + 5;
 | |
| 	for(p = a ; p < bend ; ++p)
 | |
| 		if( !isspace(*p) )
 | |
| 			if(isdigit(*p))
 | |
| 				nxtstno = 10*nxtstno + (*p - '0');
 | |
| 			else if (*p == '!') {
 | |
| 				if (!addftnsrc)
 | |
| 					bang(p+1,atend,aend,b,endcd);
 | |
| 				endcd = b;
 | |
| 				break;
 | |
| 				}
 | |
| 			else	{
 | |
| 				lineno = thislin;
 | |
| 				errstr(
 | |
| 				"nondigit in statement label field \"%.5s\"", a);
 | |
| 				nxtstno = 0;
 | |
| 				break;
 | |
| 			}
 | |
| 	firstline = thislin;
 | |
| 	return(STINITIAL);
 | |
| }
 | |
| 
 | |
| 
 | |
| /* crunch -- deletes all space characters, folds the backslash chars and
 | |
|    Hollerith strings, quotes the Fortran strings */
 | |
| 
 | |
|  LOCAL void
 | |
| crunch()
 | |
| {
 | |
| 	register char *i, *j, *j0, *j1, *prvstr;
 | |
| 	int k, ten, nh, nh0, quote;
 | |
| 
 | |
| 	/* i is the next input character to be looked at
 | |
| 	   j is the next output character */
 | |
| 
 | |
| 	new_dcl = needwkey = parlev = parseen = 0;
 | |
| 	expcom = 0;	/* exposed ','s */
 | |
| 	expeql = 0;	/* exposed equal signs */
 | |
| 	j = sbuf;
 | |
| 	prvstr = sbuf;
 | |
| 	k = 0;
 | |
| 	for(i=sbuf ; i<=lastch ; ++i)
 | |
| 	{
 | |
| 		if(isspace(*i) )
 | |
| 			continue;
 | |
| 		if (*i == '!') {
 | |
| 			while(i >= linestart[k])
 | |
| 				if (++k >= CONTMAX)
 | |
| 					Fatal("too many continuations\n");
 | |
| 			j0 = linestart[k];
 | |
| 			if (!addftnsrc)
 | |
| 				bang(sbuf,sbuf,sbuf,i+1,j0);
 | |
| 			i = j0-1;
 | |
| 			continue;
 | |
| 			}
 | |
| 
 | |
| /* Keep everything in a quoted string */
 | |
| 
 | |
| 		if(*i=='\'' ||  *i=='"')
 | |
| 		{
 | |
| 			int len = 0;
 | |
| 
 | |
| 			quote = *i;
 | |
| 			*j = MYQUOTE; /* special marker */
 | |
| 			for(;;)
 | |
| 			{
 | |
| 				if(++i > lastch)
 | |
| 				{
 | |
| 					err("unbalanced quotes; closing quote supplied");
 | |
| 					if (j >= lastch)
 | |
| 						j = lastch - 1;
 | |
| 					break;
 | |
| 				}
 | |
| 				if(*i == quote)
 | |
| 					if(i<lastch && i[1]==quote) ++i;
 | |
| 					else break;
 | |
| 				else if(*i=='\\' && i<lastch && use_bs) {
 | |
| 					++i;
 | |
| 					*i = escapes[*(unsigned char *)i];
 | |
| 					}
 | |
| 				if (len + 2 < MAXTOKENLEN)
 | |
| 				    *++j = *i;
 | |
| 				else if (len + 2 == MAXTOKENLEN)
 | |
| 				    erri
 | |
| 	    ("String too long, truncating to %d chars", MAXTOKENLEN - 2);
 | |
| 				len++;
 | |
| 			} /* for (;;) */
 | |
| 
 | |
| 			j[1] = MYQUOTE;
 | |
| 			j += 2;
 | |
| 			prvstr = j;
 | |
| 		}
 | |
| 		else if( (*i=='h' || *i=='H')  && j>prvstr)	/* test for Hollerith strings */
 | |
| 		{
 | |
| 			j0 = j - 1;
 | |
| 			if( ! isdigit(*j0)) goto copychar;
 | |
| 			nh = *j0 - '0';
 | |
| 			ten = 10;
 | |
| 			j1 = prvstr;
 | |
| 			if (j1+4 < j)
 | |
| 				j1 = j-4;
 | |
| 			for(;;) {
 | |
| 				if (j0-- <= j1)
 | |
| 					goto copychar;
 | |
| 				if( ! isdigit(*j0 ) ) break;
 | |
| 				nh += ten * (*j0-'0');
 | |
| 				ten*=10;
 | |
| 				}
 | |
| 			/* 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=='*'&&sbuf[0]=='d') && *j0!='/'
 | |
| 			&& *j0!='(' && *j0!=',' && *j0!='=' && *j0!='.')
 | |
| 				goto copychar;
 | |
| 			nh0 = nh;
 | |
| 			if(i+nh > lastch || nh + 2 > MAXTOKENLEN)
 | |
| 			{
 | |
| 				erri("%dH too big", nh);
 | |
| 				nh = lastch - i;
 | |
| 				if (nh > MAXTOKENLEN - 2)
 | |
| 					nh = MAXTOKENLEN - 2;
 | |
| 				nh0 = -1;
 | |
| 			}
 | |
| 			j0[1] = MYQUOTE; /* special marker */
 | |
| 			j = j0 + 1;
 | |
| 			while(nh-- > 0)
 | |
| 			{
 | |
| 				if (++i > lastch) {
 | |
|  hol_overflow:
 | |
| 					if (nh0 >= 0)
 | |
| 					  erri("escapes make %dH too big",
 | |
| 						nh0);
 | |
| 					break;
 | |
| 					}
 | |
| 				if(*i == '\\' && use_bs) {
 | |
| 					if (++i > lastch)
 | |
| 						goto hol_overflow;
 | |
| 					*i = escapes[*(unsigned char *)i];
 | |
| 					}
 | |
| 				*++j = *i;
 | |
| 			}
 | |
| 			j[1] = MYQUOTE;
 | |
| 			j+=2;
 | |
| 			prvstr = j;
 | |
| 		}
 | |
| 		else	{
 | |
| 			if(*i == '(') parseen = ++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 = sbuf;
 | |
| }
 | |
| 
 | |
|  LOCAL void
 | |
| analyz()
 | |
| {
 | |
| 	register char *i;
 | |
| 
 | |
| 	if(parlev != 0)
 | |
| 	{
 | |
| 		err("unbalanced parentheses, statement skipped");
 | |
| 		stkey = SUNKNOWN;
 | |
| 		lastch = sbuf - 1; /* prevent double error msg */
 | |
| 		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<lastch &&
 | |
| 		    nextch[0]=='d' && nextch[1]=='o')
 | |
| 		{
 | |
| 			stkey = SDO;
 | |
| 			nextch += 2;
 | |
| 		}
 | |
| 		else	stkey = SLET;
 | |
| 	}
 | |
| 	else if (parseen && nextch + 7 < lastch
 | |
| 			&& nextch[2] != 'u' /* screen out "double..." early */
 | |
| 			&& nextch[0] == 'd' && nextch[1] == 'o'
 | |
| 			&& ((nextch[2] >= '0' && nextch[2] <= '9')
 | |
| 				|| nextch[2] == ','
 | |
| 				|| nextch[2] == 'w'))
 | |
| 		{
 | |
| 		stkey = SDO;
 | |
| 		nextch += 2;
 | |
| 		needwkey = 1;
 | |
| 		}
 | |
| 	/* otherwise search for keyword */
 | |
| 	else	{
 | |
| 		stkey = getkwd();
 | |
| 		if(stkey==SGOTO && lastch>=nextch)
 | |
| 			if(nextch[0]=='(')
 | |
| 				stkey = SCOMPGOTO;
 | |
| 			else if(isalpha_(* USC nextch))
 | |
| 				stkey = SASGOTO;
 | |
| 	}
 | |
| 	parlev = 0;
 | |
| }
 | |
| 
 | |
| 
 | |
| 
 | |
|  LOCAL int
 | |
| getkwd()
 | |
| {
 | |
| 	register char *i, *j;
 | |
| 	register struct Keylist *pk, *pend;
 | |
| 	int k;
 | |
| 
 | |
| 	if(! isalpha_(* USC nextch) )
 | |
| 		return(SUNKNOWN);
 | |
| 	k = letter(nextch[0]);
 | |
| 	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;
 | |
| 				if(no66flag && pk->notinf66)
 | |
| 					errstr("Not a Fortran 66 keyword: %s",
 | |
| 					    pk->keyname);
 | |
| 				return(pk->keyval);
 | |
| 			}
 | |
| 		}
 | |
| 	return(SUNKNOWN);
 | |
| }
 | |
| 
 | |
| initkey()
 | |
| {
 | |
| 	register struct Keylist *p;
 | |
| 	register int i,j;
 | |
| 	register char *s;
 | |
| 
 | |
| 	for(i = 0 ; i<26 ; ++i)
 | |
| 		keystart[i] = NULL;
 | |
| 
 | |
| 	for(p = keys ; p->keyname ; ++p) {
 | |
| 		j = letter(p->keyname[0]);
 | |
| 		if(keystart[j] == NULL)
 | |
| 			keystart[j] = p;
 | |
| 		keyend[j] = p;
 | |
| 		}
 | |
| 	comstart['c'] = comstart['C'] = comstart['*'] = comstart['!'] = 1;
 | |
| 	s = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_";
 | |
| 	while(i = *s++)
 | |
| 		anum_buf[i] = 1;
 | |
| 	s = "0123456789";
 | |
| 	while(i = *s++)
 | |
| 		anum_buf[i] = 2;
 | |
| 	}
 | |
| 
 | |
|  LOCAL int
 | |
| hexcheck(key)
 | |
|  int key;
 | |
| {
 | |
| 	register int radix;
 | |
| 	register char *p;
 | |
| 	char *kind;
 | |
| 
 | |
| 	switch(key) {
 | |
| 		case 'z':
 | |
| 		case 'Z':
 | |
| 		case 'x':
 | |
| 		case 'X':
 | |
| 			radix = 16;
 | |
| 			key = SHEXCON;
 | |
| 			kind = "hexadecimal";
 | |
| 			break;
 | |
| 		case 'o':
 | |
| 		case 'O':
 | |
| 			radix = 8;
 | |
| 			key = SOCTCON;
 | |
| 			kind = "octal";
 | |
| 			break;
 | |
| 		case 'b':
 | |
| 		case 'B':
 | |
| 			radix = 2;
 | |
| 			key = SBITCON;
 | |
| 			kind = "binary";
 | |
| 			break;
 | |
| 		default:
 | |
| 			err("bad bit identifier");
 | |
| 			return(SNAME);
 | |
| 		}
 | |
| 	for(p = token; *p; p++)
 | |
| 		if (hextoi(*p) >= radix) {
 | |
| 			errstr("invalid %s character", kind);
 | |
| 			break;
 | |
| 			}
 | |
| 	return key;
 | |
| 	}
 | |
| 
 | |
| /* gettok -- moves the right amount of text from   nextch   into the   token
 | |
|    buffer.   token   initially contains garbage (leftovers from the prev token) */
 | |
| 
 | |
|  LOCAL int
 | |
| gettok()
 | |
| {
 | |
| int havdot, havexp, havdbl;
 | |
| 	int radix, val;
 | |
| 	struct Punctlist *pp;
 | |
| 	struct Dotlist *pd;
 | |
| 	register int ch;
 | |
| 
 | |
| 	char *i, *j, *n1, *p;
 | |
| 
 | |
| 	ch = * USC nextch;
 | |
| 	if(ch == (MYQUOTE))
 | |
| 	{
 | |
| 		++nextch;
 | |
| 		p = token;
 | |
| 		while(*nextch != MYQUOTE)
 | |
| 			*p++ = *nextch++;
 | |
| 		toklen = p - token;
 | |
| 		*p = 0;
 | |
| 		/* allow octal, binary, hex constants of the form 'abc'x (etc.) */
 | |
| 		if (++nextch <= lastch && isalpha_(val = * USC nextch)) {
 | |
| 			++nextch;
 | |
| 			return hexcheck(val);
 | |
| 			}
 | |
| 		return (SHOLLERITH);
 | |
| 	}
 | |
| 
 | |
| 	if(needkwd)
 | |
| 	{
 | |
| 		needkwd = 0;
 | |
| 		return( getkwd() );
 | |
| 	}
 | |
| 
 | |
| 	for(pp=puncts; pp->punchar; ++pp)
 | |
| 		if(ch == pp->punchar) {
 | |
| 			val = pp->punval;
 | |
| 			if (++nextch <= lastch)
 | |
| 			    switch(ch) {
 | |
| 				case '/':
 | |
| 					if (*nextch == '/') {
 | |
| 						nextch++;
 | |
| 						val = SCONCAT;
 | |
| 						}
 | |
| 					else if (new_dcl && parlev == 0)
 | |
| 						val = SSLASHD;
 | |
| 					return val;
 | |
| 				case '*':
 | |
| 					if (*nextch == '*') {
 | |
| 						nextch++;
 | |
| 						return SPOWER;
 | |
| 						}
 | |
| 					break;
 | |
| 				case '<':
 | |
| 					if (*nextch == '=') {
 | |
| 						nextch++;
 | |
| 						val = SLE;
 | |
| 						}
 | |
| 					if (*nextch == '>') {
 | |
| 						nextch++;
 | |
| 						val = SNE;
 | |
| 						}
 | |
| 					goto extchk;
 | |
| 				case '=':
 | |
| 					if (*nextch == '=') {
 | |
| 						nextch++;
 | |
| 						val = SEQ;
 | |
| 						goto extchk;
 | |
| 						}
 | |
| 					break;
 | |
| 				case '>':
 | |
| 					if (*nextch == '=') {
 | |
| 						nextch++;
 | |
| 						val = SGE;
 | |
| 						}
 | |
|  extchk:
 | |
| 					NOEXT("Fortran 8x comparison operator");
 | |
| 					return val;
 | |
| 				}
 | |
| 			else if (ch == '/' && new_dcl && parlev == 0)
 | |
| 				return SSLASHD;
 | |
| 			switch(val) {
 | |
| 				case SLPAR:
 | |
| 					++parlev;
 | |
| 					break;
 | |
| 				case SRPAR:
 | |
| 					--parlev;
 | |
| 				}
 | |
| 			return(val);
 | |
| 			}
 | |
| 	if(ch == '.')
 | |
| 		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_(ch) )
 | |
| 	{
 | |
| 		p = token;
 | |
| 		*p++ = *nextch++;
 | |
| 		while(nextch<=lastch)
 | |
| 			if( isalnum_(* USC nextch) )
 | |
| 				*p++ = *nextch++;
 | |
| 			else break;
 | |
| 		toklen = p - token;
 | |
| 		*p = 0;
 | |
| 		if (needwkey) {
 | |
| 			needwkey = 0;
 | |
| 			if (toklen == 5
 | |
| 				&& nextch <= lastch && *nextch == '(' /*)*/
 | |
| 				&& !strcmp(token,"while"))
 | |
| 			return(SWHILE);
 | |
| 			}
 | |
| 		if(inioctl && nextch<=lastch && *nextch=='=')
 | |
| 		{
 | |
| 			++nextch;
 | |
| 			return(SNAMEEQ);
 | |
| 		}
 | |
| 		if(toklen>8 && eqn(8,token,"function")
 | |
| 		&& isalpha_(* USC (token+8)) &&
 | |
| 		    nextch<lastch && nextch[0]=='(' &&
 | |
| 		    (nextch[1]==')' || isalpha_(* USC (nextch+1))) )
 | |
| 		{
 | |
| 			nextch -= (toklen - 8);
 | |
| 			return(SFUNCTION);
 | |
| 		}
 | |
| 
 | |
| 		if(toklen > 50)
 | |
| 		{
 | |
| 			char buff[100];
 | |
| 			sprintf(buff, toklen >= 60
 | |
| 				? "name %.56s... too long, truncated to %.*s"
 | |
| 				: "name %s too long, truncated to %.*s",
 | |
| 			    token, 50, token);
 | |
| 			err(buff);
 | |
| 			toklen = 50;
 | |
| 			token[50] = '\0';
 | |
| 		}
 | |
| 		if(toklen==1 && *nextch==MYQUOTE) {
 | |
| 			val = token[0];
 | |
| 			++nextch;
 | |
| 			for(p = token ; *nextch!=MYQUOTE ; )
 | |
| 				*p++ = *nextch++;
 | |
| 			++nextch;
 | |
| 			toklen = p - token;
 | |
| 			*p = 0;
 | |
| 			return hexcheck(val);
 | |
| 		}
 | |
| 		return(SNAME);
 | |
| 	}
 | |
| 
 | |
| 	if (isdigit(ch)) {
 | |
| 
 | |
| 		/* Check for NAG's special hex constant */
 | |
| 
 | |
| 		if (nextch[1] == '#'
 | |
| 		||  nextch[2] == '#' && isdigit(nextch[1])) {
 | |
| 
 | |
| 		    radix = atoi (nextch);
 | |
| 		    if (*++nextch != '#')
 | |
| 			nextch++;
 | |
| 		    if (radix != 2 && radix != 8 && radix != 16) {
 | |
| 		        erri("invalid base %d for constant, defaulting to hex",
 | |
| 				radix);
 | |
| 			radix = 16;
 | |
| 		    } /* if */
 | |
| 		    if (++nextch > lastch)
 | |
| 			goto badchar;
 | |
| 		    for (p = token; hextoi(*nextch) < radix;) {
 | |
| 			*p++ = *nextch++;
 | |
| 			if (nextch > lastch)
 | |
| 				break;
 | |
| 			}
 | |
| 		    toklen = p - token;
 | |
| 		    *p = 0;
 | |
| 		    return (radix == 16) ? SHEXCON : ((radix == 8) ? SOCTCON :
 | |
| 			    SBITCON);
 | |
| 		    }
 | |
| 		}
 | |
| 	else
 | |
| 		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_(* USC (nextch+1))
 | |
| 			    && isalpha_(* USC (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)
 | |
| 				if(nextch[1]=='+' || nextch[1]=='-')
 | |
| 					++nextch;
 | |
| 			if( ! isdigit(*++nextch) )
 | |
| 			{
 | |
| 				nextch = p;
 | |
| 				havdbl = havexp = NO;
 | |
| 				break;
 | |
| 			}
 | |
| 			for(++nextch ;
 | |
| 			    nextch<=lastch && isdigit(* USC nextch);
 | |
| 			    ++nextch);
 | |
| 			break;
 | |
| 		}
 | |
| 		else if( ! isdigit(* USC nextch) )
 | |
| 			break;
 | |
| 	}
 | |
| 	p = token;
 | |
| 	i = n1;
 | |
| 	while(i < nextch)
 | |
| 		*p++ = *i++;
 | |
| 	toklen = p - token;
 | |
| 	*p = 0;
 | |
| 	if(havdbl) return(SDCON);
 | |
| 	if(havdot || havexp) return(SRCON);
 | |
| 	return(SICON);
 | |
| badchar:
 | |
| 	sbuf[0] = *nextch++;
 | |
| 	return(SUNKNOWN);
 | |
| }
 | |
| 
 | |
| /* Comment buffering code */
 | |
| 
 | |
|  static void
 | |
| store_comment(str)
 | |
|  char *str;
 | |
| {
 | |
| 	int len;
 | |
| 	comment_buf *ncb;
 | |
| 
 | |
| 	if (nextcd == sbuf) {
 | |
| 		flush_comments();
 | |
| 		p1_comment(str);
 | |
| 		return;
 | |
| 		}
 | |
| 	len = strlen(str) + 1;
 | |
| 	if (cbnext + len > cblast) {
 | |
| 		if (!cbcur || !(ncb = cbcur->next)) {
 | |
| 			ncb = (comment_buf *) Alloc(sizeof(comment_buf));
 | |
| 			if (cbcur) {
 | |
| 				cbcur->last = cbnext;
 | |
| 				cbcur->next = ncb;
 | |
| 				}
 | |
| 			else {
 | |
| 				cbfirst = ncb;
 | |
| 				cbinit = ncb->buf;
 | |
| 				}
 | |
| 			ncb->next = 0;
 | |
| 			}
 | |
| 		cbcur = ncb;
 | |
| 		cbnext = ncb->buf;
 | |
| 		cblast = cbnext + COMMENT_BUF_STORE;
 | |
| 		}
 | |
| 	strcpy(cbnext, str);
 | |
| 	cbnext += len;
 | |
| 	}
 | |
| 
 | |
|  static void
 | |
| flush_comments()
 | |
| {
 | |
| 	register char *s, *s1;
 | |
| 	register comment_buf *cb;
 | |
| 	if (cbnext == cbinit)
 | |
| 		return;
 | |
| 	cbcur->last = cbnext;
 | |
| 	for(cb = cbfirst;; cb = cb->next) {
 | |
| 		for(s = cb->buf; s < cb->last; s = s1) {
 | |
| 			/* compute s1 = new s value first, since */
 | |
| 			/* p1_comment may insert nulls into s */
 | |
| 			s1 = s + strlen(s) + 1;
 | |
| 			p1_comment(s);
 | |
| 			}
 | |
| 		if (cb == cbcur)
 | |
| 			break;
 | |
| 		}
 | |
| 	cbcur = cbfirst;
 | |
| 	cbnext = cbinit;
 | |
| 	cblast = cbnext + COMMENT_BUF_STORE;
 | |
| 	}
 | |
| 
 | |
|  void
 | |
| unclassifiable()
 | |
| {
 | |
| 	register char *s, *se;
 | |
| 
 | |
| 	s = sbuf;
 | |
| 	se = lastch;
 | |
| 	if (se < sbuf)
 | |
| 		return;
 | |
| 	lastch = s - 1;
 | |
| 	if (se - s > 10)
 | |
| 		se = s + 10;
 | |
| 	for(; s < se; s++)
 | |
| 		if (*s == MYQUOTE) {
 | |
| 			se = s;
 | |
| 			break;
 | |
| 			}
 | |
| 	*se = 0;
 | |
| 	errstr("unclassifiable statement (starts \"%s\")", sbuf);
 | |
| 	}
 |