xref: /plan9-contrib/sys/src/cmd/spin/tl_lex.c (revision de2caf28f9ba1a56e70be94a699435d36eb50311)
17dd7cddfSDavid du Colombier /***** tl_spin: tl_lex.c *****/
27dd7cddfSDavid du Colombier 
3*de2caf28SDavid du Colombier /*
4*de2caf28SDavid du Colombier  * This file is part of the public release of Spin. It is subject to the
5*de2caf28SDavid du Colombier  * terms in the LICENSE file that is included in this source directory.
6*de2caf28SDavid du Colombier  * Tool documentation is available at http://spinroot.com
7*de2caf28SDavid du Colombier  *
8*de2caf28SDavid du Colombier  * Based on the translation algorithm by Gerth, Peled, Vardi, and Wolper,
9*de2caf28SDavid du Colombier  * presented at the PSTV Conference, held in 1995, Warsaw, Poland 1995.
10*de2caf28SDavid du Colombier  */
117dd7cddfSDavid du Colombier 
127dd7cddfSDavid du Colombier #include <stdlib.h>
137dd7cddfSDavid du Colombier #include <ctype.h>
147dd7cddfSDavid du Colombier #include "tl.h"
157dd7cddfSDavid du Colombier 
167dd7cddfSDavid du Colombier static Symbol	*symtab[Nhash+1];
177dd7cddfSDavid du Colombier static int	tl_lex(void);
1800d97012SDavid du Colombier extern int tl_peek(int);
197dd7cddfSDavid du Colombier 
207dd7cddfSDavid du Colombier extern YYSTYPE	tl_yylval;
217dd7cddfSDavid du Colombier extern char	yytext[];
227dd7cddfSDavid du Colombier 
237dd7cddfSDavid du Colombier #define Token(y)        tl_yylval = tl_nn(y,ZN,ZN); return y
247dd7cddfSDavid du Colombier 
257dd7cddfSDavid du Colombier static void
tl_getword(int first,int (* tst)(int))26312a1df1SDavid du Colombier tl_getword(int first, int (*tst)(int))
27*de2caf28SDavid du Colombier {	int i=0; int c;
287dd7cddfSDavid du Colombier 
297dd7cddfSDavid du Colombier 	yytext[i++] = (char ) first;
30*de2caf28SDavid du Colombier 
31*de2caf28SDavid du Colombier 	c = tl_Getchar();
32*de2caf28SDavid du Colombier 	while (c != -1 && tst(c))
33*de2caf28SDavid du Colombier 	{	yytext[i++] = (char) c;
34*de2caf28SDavid du Colombier 		c = tl_Getchar();
35*de2caf28SDavid du Colombier 	}
36*de2caf28SDavid du Colombier 
37*de2caf28SDavid du Colombier /*	while (tst(c = tl_Getchar()))
38*de2caf28SDavid du Colombier  *		yytext[i++] = c;
39*de2caf28SDavid du Colombier  */
407dd7cddfSDavid du Colombier 	yytext[i] = '\0';
417dd7cddfSDavid du Colombier 	tl_UnGetchar();
427dd7cddfSDavid du Colombier }
437dd7cddfSDavid du Colombier 
447dd7cddfSDavid du Colombier static int
tl_follow(int tok,int ifyes,int ifno)45312a1df1SDavid du Colombier tl_follow(int tok, int ifyes, int ifno)
467dd7cddfSDavid du Colombier {	int c;
477dd7cddfSDavid du Colombier 	char buf[32];
487dd7cddfSDavid du Colombier 	extern int tl_yychar;
497dd7cddfSDavid du Colombier 
507dd7cddfSDavid du Colombier 	if ((c = tl_Getchar()) == tok)
517dd7cddfSDavid du Colombier 		return ifyes;
527dd7cddfSDavid du Colombier 	tl_UnGetchar();
537dd7cddfSDavid du Colombier 	tl_yychar = c;
547dd7cddfSDavid du Colombier 	sprintf(buf, "expected '%c'", tok);
557dd7cddfSDavid du Colombier 	tl_yyerror(buf);	/* no return from here */
567dd7cddfSDavid du Colombier 	return ifno;
577dd7cddfSDavid du Colombier }
587dd7cddfSDavid du Colombier 
597dd7cddfSDavid du Colombier int
tl_yylex(void)607dd7cddfSDavid du Colombier tl_yylex(void)
617dd7cddfSDavid du Colombier {	int c = tl_lex();
627dd7cddfSDavid du Colombier #if 0
6300d97012SDavid du Colombier 	printf("c = %c (%d)\n", c, c);
647dd7cddfSDavid du Colombier #endif
657dd7cddfSDavid du Colombier 	return c;
667dd7cddfSDavid du Colombier }
677dd7cddfSDavid du Colombier 
687dd7cddfSDavid du Colombier static int
is_predicate(int z)6900d97012SDavid du Colombier is_predicate(int z)
7000d97012SDavid du Colombier {	char c, c_prev = z;
7100d97012SDavid du Colombier 	char want = (z == '{') ? '}' : ')';
7200d97012SDavid du Colombier 	int i = 0, j, nesting = 0;
7300d97012SDavid du Colombier 	char peek_buf[512];
7400d97012SDavid du Colombier 
7500d97012SDavid du Colombier 	c = tl_peek(i++);	/* look ahead without changing position */
7600d97012SDavid du Colombier 	while ((c != want || nesting > 0) && c != -1 && i < 2047)
77*de2caf28SDavid du Colombier 	{	if (islower((int) c) || c == '_')
7800d97012SDavid du Colombier 		{	peek_buf[0] = c;
7900d97012SDavid du Colombier 			j = 1;
80*de2caf28SDavid du Colombier 			while (j < (int) sizeof(peek_buf)
81*de2caf28SDavid du Colombier 			&&    (isalnum((int)(c = tl_peek(i))) || c == '_'))
8200d97012SDavid du Colombier 			{	peek_buf[j++] = c;
8300d97012SDavid du Colombier 				i++;
8400d97012SDavid du Colombier 			}
8500d97012SDavid du Colombier 			c = 0;	/* make sure we don't match on z or want on the peekahead */
8600d97012SDavid du Colombier 			if (j >= (int) sizeof(peek_buf))
8700d97012SDavid du Colombier 			{	peek_buf[j-1] = '\0';
8800d97012SDavid du Colombier 				fatal("name '%s' in ltl formula too long", peek_buf);
8900d97012SDavid du Colombier 			}
9000d97012SDavid du Colombier 			peek_buf[j] = '\0';
9100d97012SDavid du Colombier 			if (strcmp(peek_buf, "always") == 0
92*de2caf28SDavid du Colombier 			||  strcmp(peek_buf, "equivalent") == 0
9300d97012SDavid du Colombier 			||  strcmp(peek_buf, "eventually") == 0
9400d97012SDavid du Colombier 			||  strcmp(peek_buf, "until") == 0
95*de2caf28SDavid du Colombier 			||  strcmp(peek_buf, "next") == 0
96*de2caf28SDavid du Colombier 			||  strcmp(peek_buf, "c_expr") == 0)
9700d97012SDavid du Colombier 			{	return 0;
9800d97012SDavid du Colombier 			}
9900d97012SDavid du Colombier 		} else
100*de2caf28SDavid du Colombier 		{	int c_nxt = tl_peek(i);
101*de2caf28SDavid du Colombier 			if (((c == 'U' || c == 'V' || c == 'X')
102*de2caf28SDavid du Colombier 			&& !isalnum_(c_prev)
103*de2caf28SDavid du Colombier 			&& (c_nxt == -1 || !isalnum_(c_nxt)))
10400d97012SDavid du Colombier 			||  (c == '<' && c_nxt == '>')
105*de2caf28SDavid du Colombier 			||  (c == '<' && c_nxt == '-')
106*de2caf28SDavid du Colombier 			||  (c == '-' && c_nxt == '>')
10700d97012SDavid du Colombier 			||  (c == '[' && c_nxt == ']'))
10800d97012SDavid du Colombier 			{	return 0;
10900d97012SDavid du Colombier 		}	}
11000d97012SDavid du Colombier 
11100d97012SDavid du Colombier 		if (c == z)
11200d97012SDavid du Colombier 		{	nesting++;
11300d97012SDavid du Colombier 		}
11400d97012SDavid du Colombier 		if (c == want)
11500d97012SDavid du Colombier 		{	nesting--;
11600d97012SDavid du Colombier 		}
11700d97012SDavid du Colombier 		c_prev = c;
11800d97012SDavid du Colombier 		c = tl_peek(i++);
11900d97012SDavid du Colombier 	}
12000d97012SDavid du Colombier 	return 1;
12100d97012SDavid du Colombier }
12200d97012SDavid du Colombier 
12300d97012SDavid du Colombier static void
read_upto_closing(int z)12400d97012SDavid du Colombier read_upto_closing(int z)
12500d97012SDavid du Colombier {	char c, want = (z == '{') ? '}' : ')';
12600d97012SDavid du Colombier 	int i = 0, nesting = 0;
12700d97012SDavid du Colombier 
12800d97012SDavid du Colombier 	c = tl_Getchar();
12900d97012SDavid du Colombier 	while ((c != want || nesting > 0) && c != -1 && i < 2047) /* yytext is 2048 */
13000d97012SDavid du Colombier 	{	yytext[i++] = c;
13100d97012SDavid du Colombier 		if (c == z)
13200d97012SDavid du Colombier 		{	nesting++;
13300d97012SDavid du Colombier 		}
13400d97012SDavid du Colombier 		if (c == want)
13500d97012SDavid du Colombier 		{	nesting--;
13600d97012SDavid du Colombier 		}
13700d97012SDavid du Colombier 		c = tl_Getchar();
13800d97012SDavid du Colombier 	}
13900d97012SDavid du Colombier 	yytext[i] = '\0';
14000d97012SDavid du Colombier }
14100d97012SDavid du Colombier 
14200d97012SDavid du Colombier static int
tl_lex(void)1437dd7cddfSDavid du Colombier tl_lex(void)
1447dd7cddfSDavid du Colombier {	int c;
1457dd7cddfSDavid du Colombier 
1467dd7cddfSDavid du Colombier 	do {
1477dd7cddfSDavid du Colombier 		c = tl_Getchar();
1487dd7cddfSDavid du Colombier 		yytext[0] = (char ) c;
1497dd7cddfSDavid du Colombier 		yytext[1] = '\0';
1507dd7cddfSDavid du Colombier 
1517dd7cddfSDavid du Colombier 		if (c <= 0)
1527dd7cddfSDavid du Colombier 		{	Token(';');
1537dd7cddfSDavid du Colombier 		}
1547dd7cddfSDavid du Colombier 
1557dd7cddfSDavid du Colombier 	} while (c == ' ');	/* '\t' is removed in tl_main.c */
1567dd7cddfSDavid du Colombier 
15700d97012SDavid du Colombier 	if (c == '{' || c == '(')	/* new 6.0.0 */
15800d97012SDavid du Colombier 	{	if (is_predicate(c))
15900d97012SDavid du Colombier 		{	read_upto_closing(c);
16000d97012SDavid du Colombier 			tl_yylval = tl_nn(PREDICATE,ZN,ZN);
161*de2caf28SDavid du Colombier 			if (!tl_yylval)
162*de2caf28SDavid du Colombier 			{	fatal("unexpected error 4", (char *) 0);
163*de2caf28SDavid du Colombier 			}
16400d97012SDavid du Colombier 			tl_yylval->sym = tl_lookup(yytext);
16500d97012SDavid du Colombier 			return PREDICATE;
16600d97012SDavid du Colombier 	}	}
16700d97012SDavid du Colombier 
16800d97012SDavid du Colombier 	if (c == '}')
16900d97012SDavid du Colombier 	{	tl_yyerror("unexpected '}'");
17000d97012SDavid du Colombier 	}
1717dd7cddfSDavid du Colombier 	if (islower(c))
172312a1df1SDavid du Colombier 	{	tl_getword(c, isalnum_);
1737dd7cddfSDavid du Colombier 		if (strcmp("true", yytext) == 0)
1747dd7cddfSDavid du Colombier 		{	Token(TRUE);
1757dd7cddfSDavid du Colombier 		}
1767dd7cddfSDavid du Colombier 		if (strcmp("false", yytext) == 0)
1777dd7cddfSDavid du Colombier 		{	Token(FALSE);
1787dd7cddfSDavid du Colombier 		}
17900d97012SDavid du Colombier 		if (strcmp("always", yytext) == 0)
18000d97012SDavid du Colombier 		{	Token(ALWAYS);
18100d97012SDavid du Colombier 		}
18200d97012SDavid du Colombier 		if (strcmp("eventually", yytext) == 0)
18300d97012SDavid du Colombier 		{	Token(EVENTUALLY);
18400d97012SDavid du Colombier 		}
18500d97012SDavid du Colombier 		if (strcmp("until", yytext) == 0)
18600d97012SDavid du Colombier 		{	Token(U_OPER);
18700d97012SDavid du Colombier 		}
18800d97012SDavid du Colombier #ifdef NXT
18900d97012SDavid du Colombier 		if (strcmp("next", yytext) == 0)
19000d97012SDavid du Colombier 		{	Token(NEXT);
19100d97012SDavid du Colombier 		}
19200d97012SDavid du Colombier #endif
193*de2caf28SDavid du Colombier 		if (strcmp("c_expr", yytext) == 0)
194*de2caf28SDavid du Colombier 		{	Token(CEXPR);
195*de2caf28SDavid du Colombier 		}
19600d97012SDavid du Colombier 		if (strcmp("not", yytext) == 0)
19700d97012SDavid du Colombier 		{	Token(NOT);
19800d97012SDavid du Colombier 		}
1997dd7cddfSDavid du Colombier 		tl_yylval = tl_nn(PREDICATE,ZN,ZN);
200*de2caf28SDavid du Colombier 		if (!tl_yylval)
201*de2caf28SDavid du Colombier 		{	fatal("unexpected error 5", (char *) 0);
202*de2caf28SDavid du Colombier 		}
2037dd7cddfSDavid du Colombier 		tl_yylval->sym = tl_lookup(yytext);
2047dd7cddfSDavid du Colombier 		return PREDICATE;
2057dd7cddfSDavid du Colombier 	}
20600d97012SDavid du Colombier 
2077dd7cddfSDavid du Colombier 	if (c == '<')
2087dd7cddfSDavid du Colombier 	{	c = tl_Getchar();
2097dd7cddfSDavid du Colombier 		if (c == '>')
2107dd7cddfSDavid du Colombier 		{	Token(EVENTUALLY);
2117dd7cddfSDavid du Colombier 		}
2127dd7cddfSDavid du Colombier 		if (c != '-')
2137dd7cddfSDavid du Colombier 		{	tl_UnGetchar();
2147dd7cddfSDavid du Colombier 			tl_yyerror("expected '<>' or '<->'");
2157dd7cddfSDavid du Colombier 		}
2167dd7cddfSDavid du Colombier 		c = tl_Getchar();
2177dd7cddfSDavid du Colombier 		if (c == '>')
2187dd7cddfSDavid du Colombier 		{	Token(EQUIV);
2197dd7cddfSDavid du Colombier 		}
2207dd7cddfSDavid du Colombier 		tl_UnGetchar();
2217dd7cddfSDavid du Colombier 		tl_yyerror("expected '<->'");
2227dd7cddfSDavid du Colombier 	}
2237dd7cddfSDavid du Colombier 
2247dd7cddfSDavid du Colombier 	switch (c) {
225312a1df1SDavid du Colombier 	case '/' : c = tl_follow('\\', AND, '/'); break;
226312a1df1SDavid du Colombier 	case '\\': c = tl_follow('/', OR, '\\'); break;
227312a1df1SDavid du Colombier 	case '&' : c = tl_follow('&', AND, '&'); break;
228312a1df1SDavid du Colombier 	case '|' : c = tl_follow('|', OR, '|'); break;
229312a1df1SDavid du Colombier 	case '[' : c = tl_follow(']', ALWAYS, '['); break;
230312a1df1SDavid du Colombier 	case '-' : c = tl_follow('>', IMPLIES, '-'); break;
2317dd7cddfSDavid du Colombier 	case '!' : c = NOT; break;
2327dd7cddfSDavid du Colombier 	case 'U' : c = U_OPER; break;
2337dd7cddfSDavid du Colombier 	case 'V' : c = V_OPER; break;
2347dd7cddfSDavid du Colombier #ifdef NXT
2357dd7cddfSDavid du Colombier 	case 'X' : c = NEXT; break;
2367dd7cddfSDavid du Colombier #endif
2377dd7cddfSDavid du Colombier 	default  : break;
2387dd7cddfSDavid du Colombier 	}
2397dd7cddfSDavid du Colombier 	Token(c);
2407dd7cddfSDavid du Colombier }
2417dd7cddfSDavid du Colombier 
2427dd7cddfSDavid du Colombier Symbol *
tl_lookup(char * s)2437dd7cddfSDavid du Colombier tl_lookup(char *s)
2447dd7cddfSDavid du Colombier {	Symbol *sp;
245*de2caf28SDavid du Colombier 	unsigned int h = hash(s);
2467dd7cddfSDavid du Colombier 
2477dd7cddfSDavid du Colombier 	for (sp = symtab[h]; sp; sp = sp->next)
2487dd7cddfSDavid du Colombier 		if (strcmp(sp->name, s) == 0)
2497dd7cddfSDavid du Colombier 			return sp;
2507dd7cddfSDavid du Colombier 
2517dd7cddfSDavid du Colombier 	sp = (Symbol *) tl_emalloc(sizeof(Symbol));
252312a1df1SDavid du Colombier 	sp->name = (char *) tl_emalloc((int) strlen(s) + 1);
2537dd7cddfSDavid du Colombier 	strcpy(sp->name, s);
2547dd7cddfSDavid du Colombier 	sp->next = symtab[h];
2557dd7cddfSDavid du Colombier 	symtab[h] = sp;
2567dd7cddfSDavid du Colombier 
2577dd7cddfSDavid du Colombier 	return sp;
2587dd7cddfSDavid du Colombier }
2597dd7cddfSDavid du Colombier 
2607dd7cddfSDavid du Colombier Symbol *
getsym(Symbol * s)2617dd7cddfSDavid du Colombier getsym(Symbol *s)
2627dd7cddfSDavid du Colombier {	Symbol *n = (Symbol *) tl_emalloc(sizeof(Symbol));
2637dd7cddfSDavid du Colombier 
2647dd7cddfSDavid du Colombier 	n->name = s->name;
2657dd7cddfSDavid du Colombier 	return n;
2667dd7cddfSDavid du Colombier }
267