1/*	Id: lex.c,v 1.12 2008/05/11 15:28:03 ragge Exp 	*/
2/*	$NetBSD: lex.c,v 1.1.1.2 2010/06/03 18:57:50 plunky Exp $	*/
3/*
4 * Copyright(C) Caldera International Inc. 2001-2002. All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * Redistributions of source code and documentation must retain the above
11 * copyright notice, this list of conditions and the following disclaimer.
12 * Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditionsand the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * All advertising materials mentioning features or use of this software
16 * must display the following acknowledgement:
17 * 	This product includes software developed or owned by Caldera
18 *	International, Inc.
19 * Neither the name of Caldera International, Inc. nor the names of other
20 * contributors may be used to endorse or promote products derived from
21 * this software without specific prior written permission.
22 *
23 * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA
24 * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR
25 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
26 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
27 * DISCLAIMED.  IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE LIABLE
28 * FOR ANY DIRECT, INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 * HOWEVER CAUSED AND ON ANY THEORY OFLIABILITY, WHETHER IN CONTRACT,
32 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
33 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
34 * POSSIBILITY OF SUCH DAMAGE.
35 */
36#include "defines.h"
37#include "defs.h"
38
39#include "gram.h"
40
41# define BLANK	' '
42# define MYQUOTE (2)
43# define SEOF 0
44
45/* card types */
46
47# define STEOF 1
48# define STINITIAL 2
49# define STCONTINUE 3
50
51/* lex states */
52
53#define NEWSTMT	1
54#define FIRSTTOKEN	2
55#define OTHERTOKEN	3
56#define RETEOS	4
57
58
59LOCAL int stkey;
60LOCAL int stno;
61LOCAL long int nxtstno;
62LOCAL int parlev;
63LOCAL int expcom;
64LOCAL int expeql;
65LOCAL char *nextch;
66LOCAL char *lastch;
67LOCAL char *nextcd 	= NULL;
68LOCAL char *endcd;
69LOCAL int prevlin;
70LOCAL int thislin;
71LOCAL int code;
72LOCAL int lexstate	= NEWSTMT;
73LOCAL char s[1390];
74LOCAL char *send	= s+20*66;
75LOCAL int nincl	= 0;
76
77struct inclfile
78	{
79	struct inclfile *inclnext;
80	FILEP inclfp;
81	char *inclname;
82	int incllno;
83	char *incllinp;
84	int incllen;
85	int inclcode;
86	ftnint inclstno;
87	} ;
88
89LOCAL struct inclfile *inclp	=  NULL;
90struct keylist { char *keyname; int keyval; } ;
91struct punctlist { char punchar; int punval; };
92struct fmtlist { char fmtchar; int fmtval; };
93struct dotlist { char *dotname; int dotval; };
94LOCAL struct dotlist  dots[];
95LOCAL struct keylist *keystart[26], *keyend[26];
96LOCAL struct keylist  keys[];
97
98LOCAL int getcds(void);
99LOCAL void crunch(void);
100LOCAL void analyz(void);
101LOCAL int gettok(void);
102LOCAL int getcd(char *b);
103LOCAL int getkwd(void);
104LOCAL int popinclude(void);
105
106/*
107 * called from main() to start parsing.
108 * name[0] may be \0 if stdin.
109 */
110int
111inilex(char *name)
112{
113	nincl = 0;
114	inclp = NULL;
115	doinclude(name);
116	lexstate = NEWSTMT;
117	return(NO);
118}
119
120
121
122/* throw away the rest of the current line */
123void
124flline()
125{
126lexstate = RETEOS;
127}
128
129
130
131char *lexline(n)
132ftnint *n;
133{
134*n = (lastch - nextch) + 1;
135return(nextch);
136}
137
138
139
140
141void
142doinclude(char *name)
143{
144	FILEP fp;
145	struct inclfile *t;
146
147	if(inclp) {
148		inclp->incllno = thislin;
149		inclp->inclcode = code;
150		inclp->inclstno = nxtstno;
151		if(nextcd)
152			inclp->incllinp =
153			    copyn(inclp->incllen = endcd-nextcd , nextcd);
154		else
155			inclp->incllinp = 0;
156	}
157	nextcd = NULL;
158
159	if(++nincl >= MAXINCLUDES)
160		fatal("includes nested too deep");
161	if(name[0] == '\0')
162		fp = stdin;
163	else
164		fp = fopen(name, "r");
165	if( fp ) {
166		t = inclp;
167		inclp = ALLOC(inclfile);
168		inclp->inclnext = t;
169		prevlin = thislin = 0;
170		infname = inclp->inclname = name;
171		infile = inclp->inclfp = fp;
172	} else {
173		fprintf(diagfile, "Cannot open file %s", name);
174		done(1);
175	}
176}
177
178
179
180
181LOCAL int
182popinclude()
183{
184	struct inclfile *t;
185	register char *p;
186	register int k;
187
188	if(infile != stdin)
189		fclose(infile);
190	ckfree(infname);
191
192	--nincl;
193	t = inclp->inclnext;
194	ckfree(inclp);
195	inclp = t;
196	if(inclp == NULL)
197		return(NO);
198
199	infile = inclp->inclfp;
200	infname = inclp->inclname;
201	prevlin = thislin = inclp->incllno;
202	code = inclp->inclcode;
203	stno = nxtstno = inclp->inclstno;
204	if(inclp->incllinp) {
205		endcd = nextcd = s;
206		k = inclp->incllen;
207		p = inclp->incllinp;
208		while(--k >= 0)
209			*endcd++ = *p++;
210		ckfree(inclp->incllinp);
211	} else
212		nextcd = NULL;
213	return(YES);
214}
215
216
217
218int
219yylex()
220{
221static int  tokno;
222
223	switch(lexstate)
224	{
225case NEWSTMT :	/* need a new statement */
226	if(getcds() == STEOF)
227		return(SEOF);
228	crunch();
229	tokno = 0;
230	lexstate = FIRSTTOKEN;
231	yylval.num = stno;
232	stno = nxtstno;
233	toklen = 0;
234	return(SLABEL);
235
236first:
237case FIRSTTOKEN :	/* first step on a statement */
238	analyz();
239	lexstate = OTHERTOKEN;
240	tokno = 1;
241	return(stkey);
242
243case OTHERTOKEN :	/* return next token */
244	if(nextch > lastch)
245		goto reteos;
246	++tokno;
247	if((stkey==SLOGIF || stkey==SELSEIF) && parlev==0 && tokno>3) goto first;
248	if(stkey==SASSIGN && tokno==3 && nextch<lastch &&
249		nextch[0]=='t' && nextch[1]=='o')
250			{
251			nextch+=2;
252			return(STO);
253			}
254	return(gettok());
255
256reteos:
257case RETEOS:
258	lexstate = NEWSTMT;
259	return(SEOS);
260	}
261fatal1("impossible lexstate %d", lexstate);
262/* NOTREACHED */
263return 0; /* XXX gcc */
264}
265
266LOCAL int
267getcds()
268{
269register char *p, *q;
270
271top:
272	if(nextcd == NULL)
273		{
274		code = getcd( nextcd = s );
275		stno = nxtstno;
276		prevlin = thislin;
277		}
278	if(code == STEOF) {
279		if( popinclude() )
280			goto top;
281		else
282			return(STEOF);
283	}
284	if(code == STCONTINUE)
285		{
286		lineno = thislin;
287		err("illegal continuation card ignored");
288		nextcd = NULL;
289		goto top;
290		}
291
292	if(nextcd > s)
293		{
294		q = nextcd;
295		p = s;
296		while(q < endcd)
297			*p++ = *q++;
298		endcd = p;
299		}
300	for(nextcd = endcd ;
301		nextcd+66<=send && (code = getcd(nextcd))==STCONTINUE ;
302		nextcd = endcd )
303			;
304	nextch = s;
305	lastch = nextcd - 1;
306	if(nextcd >= send)
307		nextcd = NULL;
308	lineno = prevlin;
309	prevlin = thislin;
310	return(STINITIAL);
311}
312
313LOCAL int
314getcd(b)
315register char *b;
316{
317register int c;
318register char *p, *bend;
319int speclin;
320static char a[6];
321static char *aend	= a+6;
322
323top:
324	endcd = b;
325	bend = b+66;
326	speclin = NO;
327
328	if( (c = getc(infile)) == '&')
329		{
330		a[0] = BLANK;
331		a[5] = 'x';
332		speclin = YES;
333		bend = send;
334		}
335	else if(c=='c' || c=='C' || c=='*')
336		{
337		while( (c = getc(infile)) != '\n')
338			if(c == EOF)
339				return(STEOF);
340		++thislin;
341		goto top;
342		}
343
344	else if(c != EOF)
345		{
346		/* a tab in columns 1-6 skips to column 7 */
347		ungetc(c, infile);
348		for(p=a; p<aend && (c=getc(infile)) != '\n' && c!=EOF; )
349			if(c == '\t')
350				{
351				while(p < aend)
352					*p++ = BLANK;
353				speclin = YES;
354				bend = send;
355				}
356			else
357				*p++ = c;
358		}
359	if(c == EOF)
360		return(STEOF);
361	if(c == '\n')
362		{
363		p = a; /* XXX ??? */
364		while(p < aend)
365			*p++ = BLANK;
366		if( ! speclin )
367			while(endcd < bend)
368				*endcd++ = BLANK;
369		}
370	else	{	/* read body of line */
371		while( endcd<bend && (c=getc(infile)) != '\n' && c!=EOF )
372			*endcd++ = (c == '\t' ? BLANK : c);
373		if(c == EOF)
374			return(STEOF);
375		if(c != '\n')
376			{
377			while( (c=getc(infile)) != '\n')
378				if(c == EOF)
379					return(STEOF);
380			}
381
382		if( ! speclin )
383			while(endcd < bend)
384				*endcd++ = BLANK;
385		}
386	++thislin;
387	if(a[5]!=BLANK && a[5]!='0')
388		return(STCONTINUE);
389	for(p=a; p<aend; ++p)
390		if(*p != BLANK) goto initline;
391	for(p = b ; p<endcd ; ++p)
392		if(*p != BLANK) goto initline;
393	goto top;
394
395initline:
396	nxtstno = 0;
397	for(p = a ; p<a+5 ; ++p)
398		if(*p != BLANK) {
399			if(isdigit((int)*p))
400				nxtstno = 10*nxtstno + (*p - '0');
401			else	{
402				lineno = thislin;
403				err("nondigit in statement number field");
404				nxtstno = 0;
405				break;
406				}
407		}
408	return(STINITIAL);
409}
410
411LOCAL void
412crunch()
413{
414register char *i, *j, *j0, *j1, *prvstr;
415int ten, nh, quote;
416
417/* i is the next input character to be looked at
418j is the next output character */
419parlev = 0;
420expcom = 0;	/* exposed ','s */
421expeql = 0;	/* exposed equal signs */
422j = s;
423prvstr = s;
424for(i=s ; i<=lastch ; ++i)
425	{
426	if(*i == BLANK) continue;
427	if(*i=='\'' ||  *i=='"')
428		{
429		quote = *i;
430		*j = MYQUOTE; /* special marker */
431		for(;;)
432			{
433			if(++i > lastch)
434				{
435				err("unbalanced quotes; closing quote supplied");
436				break;
437				}
438			if(*i == quote)
439				if(i<lastch && i[1]==quote) ++i;
440				else break;
441			else if(*i=='\\' && i<lastch)
442				switch(*++i)
443					{
444					case 't':
445						*i = '\t'; break;
446					case 'b':
447						*i = '\b'; break;
448					case 'n':
449						*i = '\n'; break;
450					case 'f':
451						*i = '\f'; break;
452					case '0':
453						*i = '\0'; break;
454					default:
455						break;
456					}
457			*++j = *i;
458			}
459		j[1] = MYQUOTE;
460		j += 2;
461		prvstr = j;
462		}
463	else if( (*i=='h' || *i=='H')  && j>prvstr)	/* test for Hollerith strings */
464		{
465		if( ! isdigit((int)j[-1])) goto copychar;
466		nh = j[-1] - '0';
467		ten = 10;
468		j1 = prvstr - 1;
469		if (j1<j-5) j1=j-5;
470		for(j0=j-2 ; j0>j1; -- j0)
471			{
472			if( ! isdigit((int)*j0 ) ) break;
473			nh += ten * (*j0-'0');
474			ten*=10;
475			}
476		if(j0 <= j1) goto copychar;
477/* a hollerith must be preceded by a punctuation mark.
478   '*' is possible only as repetition factor in a data statement
479   not, in particular, in character*2h
480*/
481
482		if( !(*j0=='*'&&s[0]=='d') && *j0!='/' && *j0!='(' &&
483			*j0!=',' && *j0!='=' && *j0!='.')
484				goto copychar;
485		if(i+nh > lastch)
486			{
487			err1("%dH too big", nh);
488			nh = lastch - i;
489			}
490		j0[1] = MYQUOTE; /* special marker */
491		j = j0 + 1;
492		while(nh-- > 0)
493			{
494			if(*++i == '\\')
495				switch(*++i)
496					{
497					case 't':
498						*i = '\t'; break;
499					case 'b':
500						*i = '\b'; break;
501					case 'n':
502						*i = '\n'; break;
503					case 'f':
504						*i = '\f'; break;
505					case '0':
506						*i = '\0'; break;
507					default:
508						break;
509					}
510			*++j = *i;
511			}
512		j[1] = MYQUOTE;
513		j+=2;
514		prvstr = j;
515		}
516	else	{
517		if(*i == '(') ++parlev;
518		else if(*i == ')') --parlev;
519		else if(parlev == 0) {
520			if(*i == '=') expeql = 1;
521			else if(*i == ',') expcom = 1;
522copychar:	;	/*not a string of BLANK -- copy, shifting case if necessary */
523		}
524		if(shiftcase && isupper((int)*i))
525			*j++ = tolower((int)*i);
526		else	*j++ = *i;
527		}
528	}
529lastch = j - 1;
530nextch = s;
531}
532
533LOCAL void
534analyz()
535{
536register char *i;
537
538	if(parlev != 0)
539		{
540		err("unbalanced parentheses, statement skipped");
541		stkey = SUNKNOWN;
542		return;
543		}
544	if(nextch+2<=lastch && nextch[0]=='i' && nextch[1]=='f' && nextch[2]=='(')
545		{
546/* assignment or if statement -- look at character after balancing paren */
547		parlev = 1;
548		for(i=nextch+3 ; i<=lastch; ++i)
549			if(*i == (MYQUOTE))
550				{
551				while(*++i != MYQUOTE)
552					;
553				}
554			else if(*i == '(')
555				++parlev;
556			else if(*i == ')')
557				{
558				if(--parlev == 0)
559					break;
560				}
561		if(i >= lastch)
562			stkey = SLOGIF;
563		else if(i[1] == '=')
564			stkey = SLET;
565		else if( isdigit((int)i[1]) )
566			stkey = SARITHIF;
567		else	stkey = SLOGIF;
568		if(stkey != SLET)
569			nextch += 2;
570		}
571	else if(expeql) /* may be an assignment */
572		{
573		if(expcom && nextch<lastch &&
574			nextch[0]=='d' && nextch[1]=='o')
575				{
576				stkey = SDO;
577				nextch += 2;
578				}
579		else	stkey = SLET;
580		}
581/* otherwise search for keyword */
582	else	{
583		stkey = getkwd();
584		if(stkey==SGOTO && lastch>=nextch) {
585			if(nextch[0]=='(')
586				stkey = SCOMPGOTO;
587			else if(isalpha((int)nextch[0]))
588				stkey = SASGOTO;
589		}
590	}
591	parlev = 0;
592}
593
594
595
596LOCAL int
597getkwd()
598{
599register char *i, *j;
600register struct keylist *pk, *pend;
601int k;
602
603if(! isalpha((int)nextch[0]) )
604	return(SUNKNOWN);
605k = nextch[0] - 'a';
606if((pk = keystart[k]))
607	for(pend = keyend[k] ; pk<=pend ; ++pk )
608		{
609		i = pk->keyname;
610		j = nextch;
611		while(*++i==*++j && *i!='\0')
612			;
613		if(*i == '\0')
614			{
615			nextch = j;
616			return(pk->keyval);
617			}
618		}
619return(SUNKNOWN);
620}
621
622
623void
624initkey()
625{
626register struct keylist *p;
627register int i,j;
628
629for(i = 0 ; i<26 ; ++i)
630	keystart[i] = NULL;
631
632for(p = keys ; p->keyname ; ++p)
633	{
634	j = p->keyname[0] - 'a';
635	if(keystart[j] == NULL)
636		keystart[j] = p;
637	keyend[j] = p;
638	}
639}
640
641LOCAL int
642gettok()
643{
644int havdot, havexp, havdbl;
645int radix;
646extern struct punctlist puncts[];
647struct punctlist *pp;
648#if 0
649extern struct fmtlist fmts[];
650#endif
651struct dotlist *pd;
652
653char *i, *j, *n1, *p;
654
655	if(*nextch == (MYQUOTE))
656		{
657		++nextch;
658		p = token;
659		while(*nextch != MYQUOTE)
660			*p++ = *nextch++;
661		++nextch;
662		toklen = p - token;
663		*p = '\0';
664		return (SHOLLERITH);
665		}
666/*
667	if(stkey == SFORMAT)
668		{
669		for(pf = fmts; pf->fmtchar; ++pf)
670			{
671			if(*nextch == pf->fmtchar)
672				{
673				++nextch;
674				if(pf->fmtval == SLPAR)
675					++parlev;
676				else if(pf->fmtval == SRPAR)
677					--parlev;
678				return(pf->fmtval);
679				}
680			}
681		if( isdigit(*nextch) )
682			{
683			p = token;
684			*p++ = *nextch++;
685			while(nextch<=lastch && isdigit(*nextch) )
686				*p++ = *nextch++;
687			toklen = p - token;
688			*p = '\0';
689			if(nextch<=lastch && *nextch=='p')
690				{
691				++nextch;
692				return(SSCALE);
693				}
694			else	return(SICON);
695			}
696		if( isalpha(*nextch) )
697			{
698			p = token;
699			*p++ = *nextch++;
700			while(nextch<=lastch &&
701				(*nextch=='.' || isdigit(*nextch) || isalpha(*nextch) ))
702					*p++ = *nextch++;
703			toklen = p - token;
704			*p = '\0';
705			return(SFIELD);
706			}
707		goto badchar;
708		}
709 XXX ??? */
710/* Not a format statement */
711
712if(needkwd)
713	{
714	needkwd = 0;
715	return( getkwd() );
716	}
717
718	for(pp=puncts; pp->punchar; ++pp)
719		if(*nextch == pp->punchar)
720			{
721			if( (*nextch=='*' || *nextch=='/') &&
722				nextch<lastch && nextch[1]==nextch[0])
723					{
724					if(*nextch == '*')
725						yylval.num = SPOWER;
726					else	yylval.num = SCONCAT;
727					nextch+=2;
728					}
729			else	{yylval.num=pp->punval;
730					if(yylval.num==SLPAR)
731						++parlev;
732					else if(yylval.num==SRPAR)
733						--parlev;
734					++nextch;
735				}
736			return(yylval.num);
737			}
738	if(*nextch == '.') {
739		if(nextch >= lastch) goto badchar;
740		else if(isdigit((int)nextch[1])) goto numconst;
741		else	{
742			for(pd=dots ; (j=pd->dotname) ; ++pd)
743				{
744				for(i=nextch+1 ; i<=lastch ; ++i)
745					if(*i != *j) break;
746					else if(*i != '.') ++j;
747					else	{
748						nextch = i+1;
749						return(pd->dotval);
750						}
751				}
752			goto badchar;
753			}
754	}
755	if( isalpha((int)*nextch) )
756		{
757		p = token;
758		*p++ = *nextch++;
759		while(nextch<=lastch)
760			if( isalpha((int)*nextch) || isdigit((int)*nextch) )
761				*p++ = *nextch++;
762			else break;
763		toklen = p - token;
764		*p = '\0';
765		if(inioctl && nextch<=lastch && *nextch=='=')
766			{
767			++nextch;
768			return(SNAMEEQ);
769			}
770		if(toklen>=8 && eqn(8, token, "function") &&
771			nextch<lastch && *nextch=='(')
772				{
773				nextch -= (toklen - 8);
774				return(SFUNCTION);
775				}
776		if(toklen > VL)
777			{
778			err2("name %s too long, truncated to %d", token, VL);
779			toklen = VL;
780			token[6] = '\0';
781			}
782		if(toklen==1 && *nextch==MYQUOTE)
783			{
784			switch(token[0])
785				{
786				case 'z':  case 'Z':
787				case 'x':  case 'X':
788					radix = 16; break;
789				case 'o':  case 'O':
790					radix = 8; break;
791				case 'b':  case 'B':
792					radix = 2; break;
793				default:
794					err("bad bit identifier");
795					return(SFNAME);
796				}
797			++nextch;
798			for(p = token ; *nextch!=MYQUOTE ; )
799				if( hextoi(*p++ = *nextch++) >= radix)
800					{
801					err("invalid binary character");
802					break;
803					}
804			++nextch;
805			toklen = p - token;
806			return( radix==16 ? SHEXCON : (radix==8 ? SOCTCON : SBITCON) );
807			}
808		return(SFNAME);
809		}
810	if( ! isdigit((int)*nextch) ) goto badchar;
811numconst:
812	havdot = NO;
813	havexp = NO;
814	havdbl = NO;
815	for(n1 = nextch ; nextch<=lastch ; ++nextch)
816		{
817		if(*nextch == '.')
818			if(havdot) break;
819			else if(nextch+2<=lastch && isalpha((int)nextch[1])
820				&& isalpha((int)nextch[2]))
821					break;
822			else	havdot = YES;
823		else if(*nextch=='d' || *nextch=='e')
824			{
825			p = nextch;
826			havexp = YES;
827			if(*nextch == 'd')
828				havdbl = YES;
829			if(nextch<lastch)
830				if(nextch[1]=='+' || nextch[1]=='-')
831					++nextch;
832			if( ! isdigit((int)*++nextch) )
833				{
834				nextch = p;
835				havdbl = havexp = NO;
836				break;
837				}
838			for(++nextch ;
839				nextch<=lastch && isdigit((int)*nextch);
840				++nextch);
841			break;
842			}
843		else if( ! isdigit((int)*nextch) )
844			break;
845		}
846	p = token;
847	i = n1;
848	while(i < nextch)
849		*p++ = *i++;
850	toklen = p - token;
851	*p = '\0';
852	if(havdbl) return(SDCON);
853	if(havdot || havexp) return(SRCON);
854	return(SICON);
855badchar:
856	s[0] = *nextch++;
857	return(SUNKNOWN);
858}
859
860/* KEYWORD AND SPECIAL CHARACTER TABLES
861*/
862
863struct punctlist puncts[ ] =
864	{
865{	'(', SLPAR, },
866{	')', SRPAR, },
867{	'=', SEQUALS, },
868{	',', SCOMMA, },
869{	'+', SPLUS, },
870{	'-', SMINUS, },
871{	'*', SSTAR, },
872{	'/', SSLASH, },
873{	'$', SCURRENCY, },
874{	':', SCOLON, },
875{	0, 0 }, } ;
876
877/*
878LOCAL struct fmtlist  fmts[ ] =
879	{
880	'(', SLPAR,
881	')', SRPAR,
882	'/', SSLASH,
883	',', SCOMMA,
884	'-', SMINUS,
885	':', SCOLON,
886	0, 0 } ;
887*/
888
889LOCAL struct dotlist  dots[ ] =
890	{
891{	"and.", SAND, },
892{	"or.", SOR, },
893{	"not.", SNOT, },
894{	"true.", STRUE, },
895{	"false.", SFALSE, },
896{	"eq.", SEQ, },
897{	"ne.", SNE, },
898{	"lt.", SLT, },
899{	"le.", SLE, },
900{	"gt.", SGT, },
901{	"ge.", SGE, },
902{	"neqv.", SNEQV, },
903{	"eqv.", SEQV, },
904{	0, 0 }, } ;
905
906LOCAL struct keylist  keys[ ] =
907	{
908{	"assign",  SASSIGN, },
909{	"automatic",  SAUTOMATIC, },
910{	"backspace",  SBACKSPACE, },
911{	"blockdata",  SBLOCK, },
912{	"call",  SCALL, },
913{	"character",  SCHARACTER, },
914{	"close",  SCLOSE, },
915{	"common",  SCOMMON, },
916{	"complex",  SCOMPLEX, },
917{	"continue",  SCONTINUE, },
918{	"data",  SDATA, },
919{	"dimension",  SDIMENSION, },
920{	"doubleprecision",  SDOUBLE, },
921{	"doublecomplex", SDCOMPLEX, },
922{	"elseif",  SELSEIF, },
923{	"else",  SELSE, },
924{	"endfile",  SENDFILE, },
925{	"endif",  SENDIF, },
926{	"end",  SEND, },
927{	"entry",  SENTRY, },
928{	"equivalence",  SEQUIV, },
929{	"external",  SEXTERNAL, },
930{	"format",  SFORMAT, },
931{	"function",  SFUNCTION, },
932{	"goto",  SGOTO, },
933{	"implicit",  SIMPLICIT, },
934{	"include",  SINCLUDE, },
935{	"inquire",  SINQUIRE, },
936{	"intrinsic",  SINTRINSIC, },
937{	"integer",  SINTEGER, },
938{	"logical",  SLOGICAL, },
939{	"open",  SOPEN, },
940{	"parameter",  SPARAM, },
941{	"pause",  SPAUSE, },
942{	"print",  SPRINT, },
943{	"program",  SPROGRAM, },
944{	"punch",  SPUNCH, },
945{	"read",  SREAD, },
946{	"real",  SREAL, },
947{	"return",  SRETURN, },
948{	"rewind",  SREWIND, },
949{	"save",  SSAVE, },
950{	"static",  SSTATIC, },
951{	"stop",  SSTOP, },
952{	"subroutine",  SSUBROUTINE, },
953{	"then",  STHEN, },
954{	"undefined", SUNDEFINED, },
955{	"write",  SWRITE, },
956{	0, 0 }, };
957