1%{
2/*
3 * CDDL HEADER START
4 *
5 * The contents of this file are subject to the terms of the
6 * Common Development and Distribution License, Version 1.0 only
7 * (the "License").  You may not use this file except in compliance
8 * with the License.
9 *
10 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
11 * or http://www.opensolaris.org/os/licensing.
12 * See the License for the specific language governing permissions
13 * and limitations under the License.
14 *
15 * When distributing Covered Code, include this CDDL HEADER in each
16 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
17 * If applicable, add the following below this CDDL HEADER, with the
18 * fields enclosed by brackets "[]" replaced with your own identifying
19 * information: Portions Copyright [yyyy] [name of copyright owner]
20 *
21 * CDDL HEADER END
22 */
23%}
24/*
25 * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
26 * Use is subject to license terms.
27 */
28
29/*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
30/*	  All Rights Reserved	*/
31
32%{
33#pragma ident	"%Z%%M%	%I%	%E% SMI"
34%}
35
36/* Yacc productions for "expr" command: */
37
38%{
39typedef	char *yystype;
40#define	YYSTYPE	yystype
41%}
42
43%token OR AND ADD SUBT MULT DIV REM EQ GT GEQ LT LEQ NEQ
44%token A_STRING SUBSTR LENGTH INDEX NOARG MATCH
45
46/* operators listed below in increasing precedence: */
47%left OR
48%left AND
49%left EQ LT GT GEQ LEQ NEQ
50%left ADD SUBT
51%left MULT DIV REM
52%left MCH
53%left MATCH
54%left SUBSTR
55%left LENGTH INDEX
56%%
57
58/* a single `expression' is evaluated and printed: */
59
60expression:	expr NOARG = {
61			printf("%s\n", $1);
62			exit((!strcmp($1,"0")||!strcmp($1,"\0"))? 1: 0);
63			}
64	;
65
66
67expr:	'(' expr ')' = { $$ = $2; }
68	| expr OR expr   = { $$ = conj(OR, $1, $3); }
69	| expr AND expr   = { $$ = conj(AND, $1, $3); }
70	| expr EQ expr   = { $$ = rel(EQ, $1, $3); }
71	| expr GT expr   = { $$ = rel(GT, $1, $3); }
72	| expr GEQ expr   = { $$ = rel(GEQ, $1, $3); }
73	| expr LT expr   = { $$ = rel(LT, $1, $3); }
74	| expr LEQ expr   = { $$ = rel(LEQ, $1, $3); }
75	| expr NEQ expr   = { $$ = rel(NEQ, $1, $3); }
76	| expr ADD expr   = { $$ = arith(ADD, $1, $3); }
77	| expr SUBT expr   = { $$ = arith(SUBT, $1, $3); }
78	| expr MULT expr   = { $$ = arith(MULT, $1, $3); }
79	| expr DIV expr   = { $$ = arith(DIV, $1, $3); }
80	| expr REM expr   = { $$ = arith(REM, $1, $3); }
81	| expr MCH expr	 = { $$ = match($1, $3); }
82	| MATCH expr expr = { $$ = match($2, $3); }
83	| SUBSTR expr expr expr = { $$ = substr($2, $3, $4); }
84	| LENGTH expr       = { $$ = length($2); }
85	| INDEX expr expr = { $$ = index($2, $3); }
86	| A_STRING
87	;
88%%
89
90#define ESIZE	256
91#define EQL(x,y) !strcmp(x,y)
92
93#define INIT	char *sp = instring;
94#define GETC()		(*sp++)
95#define PEEKC()		(*sp)
96#define UNGETC(c)	(--sp)
97#define RETURN(c)	return(c)
98#define ERROR(c)	errxx(c)
99#include  <regexp.h>
100#include  <malloc.h>
101#include  <stdlib.h>
102
103char	**Av;
104int	Ac;
105int	Argi;
106
107char *ltoa(long l);
108
109char Mstring[1][128];
110
111
112char *operator[] = {
113	"|", "&", "+", "-", "*", "/", "%", ":",
114	"=", "==", "<", "<=", ">", ">=", "!=",
115	"match", "substr", "length", "index", "\0" };
116int op[] = {
117	OR, AND, ADD,  SUBT, MULT, DIV, REM, MCH,
118	EQ, EQ, LT, LEQ, GT, GEQ, NEQ,
119	MATCH, SUBSTR, LENGTH, INDEX };
120int
121yylex(void)
122{
123	char *p;
124	int i;
125
126	if(Argi >= Ac) return NOARG;
127
128	p = Av[Argi++];
129
130	if((*p == '(' || *p == ')') && p[1] == '\0' )
131		return (int)*p;
132	for(i = 0; *operator[i]; ++i)
133		if(EQL(operator[i], p))
134			return op[i];
135
136	yylval = p;
137	return A_STRING;
138}
139
140char *
141rel(int oper, char *r1, char *r2)
142{
143	long i;
144
145	if(ematch(r1, "-\\{0,1\\}[0-9]*$") && ematch(r2, "-\\{0,1\\}[0-9]*$"))
146		i = atol(r1) - atol(r2);
147	else
148		i = strcmp(r1, r2);
149	switch(oper) {
150	case EQ:
151		i = i==0;
152		break;
153	case GT:
154		i = i>0;
155		break;
156	case GEQ:
157		i = i>=0;
158		break;
159	case LT:
160		i = i<0;
161		break;
162	case LEQ:
163		i = i<=0;
164		break;
165	case NEQ:
166		i = i!=0;
167		break;
168	}
169	return i? "1": "0";
170}
171
172char *arith(oper, r1, r2) char *r1, *r2;
173{
174	long i1, i2;
175	char *rv;
176
177	if(!(ematch(r1, "-\\{0,1\\}[0-9]*$") && ematch(r2, "-\\{0,1\\}[0-9]*$")))
178		yyerror("non-numeric argument");
179	i1 = atol(r1);
180	i2 = atol(r2);
181
182	switch(oper) {
183	case ADD:
184		i1 = i1 + i2;
185		break;
186	case SUBT:
187		i1 = i1 - i2;
188		break;
189	case MULT:
190		i1 = i1 * i2;
191		break;
192	case DIV:
193		if (i2 == 0)
194			yyerror("division by zero");
195		i1 = i1 / i2;
196		break;
197	case REM:
198		if (i2 == 0)
199			yyerror("division by zero");
200		i1 = i1 % i2;
201		break;
202	}
203	rv = malloc(16);
204	(void) strcpy(rv, ltoa(i1));
205	return rv;
206}
207char *conj(oper, r1, r2) char *r1, *r2;
208{
209	char *rv;
210
211	switch(oper) {
212
213	case OR:
214		if(EQL(r1, "0")
215		    || EQL(r1, ""))
216			if(EQL(r2, "0")
217			    || EQL(r2, ""))
218				rv = "0";
219			else
220				rv = r2;
221		else
222			rv = r1;
223		break;
224	case AND:
225		if(EQL(r1, "0")
226		    || EQL(r1, ""))
227			rv = "0";
228		else if(EQL(r2, "0")
229		    || EQL(r2, ""))
230			rv = "0";
231		else
232			rv = r1;
233		break;
234	}
235	return rv;
236}
237
238char *
239substr(char *v, char *s, char *w)
240{
241	int si, wi;
242	char *res;
243
244	si = atol(s);
245	wi = atol(w);
246	while(--si) if(*v) ++v;
247
248	res = v;
249
250	while(wi--) if(*v) ++v;
251
252	*v = '\0';
253	return res;
254}
255
256char *
257index(char *s, char *t)
258{
259	long i, j;
260	char *rv;
261
262	for(i = 0; s[i] ; ++i)
263		for(j = 0; t[j] ; ++j)
264			if(s[i]==t[j]) {
265				(void) strcpy(rv = malloc(8), ltoa(++i));
266				return rv;
267			}
268	return "0";
269}
270
271char *
272length(char *s)
273{
274	long i = 0;
275	char *rv;
276
277	while(*s++) ++i;
278
279	rv = malloc(8);
280	(void) strcpy(rv, ltoa(i));
281	return rv;
282}
283
284char *
285match(char *s, char *p)
286{
287	char *rv;
288
289	(void) strcpy(rv=malloc(8), ltoa((long)ematch(s, p)));
290	if(nbra) {
291		rv = malloc((unsigned) strlen(Mstring[0]) + 1);
292		(void) strcpy(rv, Mstring[0]);
293	}
294	return rv;
295}
296
297int
298ematch(char *s, char *p)
299{
300	static char expbuf[ESIZE];
301	char *compile();
302	int num;
303	extern char *braslist[], *braelist[], *loc2;
304
305	compile(p, expbuf, &expbuf[ESIZE], 0);
306	if(nbra > 1)
307		yyerror("Too many '\\('s");
308	if(advance(s, expbuf)) {
309		if(nbra == 1) {
310			p = braslist[0];
311			num = braelist[0] - p;
312			if ((num > 127) || (num < 0)) yyerror("Paren problem");
313			(void) strncpy(Mstring[0], p, num);
314			Mstring[0][num] = '\0';
315		}
316		return(loc2-s);
317	}
318	return(0);
319}
320
321int
322errxx(int err)
323{
324	char *message;
325
326	switch(err) {
327		case 11:
328			message = "Range endpoint too large";
329			break;
330		case 16:
331			message = "Bad number";
332			break;
333		case 25:
334			message = "``\\digit'' out of range";
335			break;
336		case 36:
337			message = "Illegal or missing delimiter";
338			break;
339		case 41:
340			message = "No remembered search string";
341			break;
342		case 42:
343			message = "\\( \\) imbalance";
344			break;
345		case 43:
346			message = "Too many \\(";
347			break;
348		case 44:
349			message = "More than 2 numbers given in \\{ \\}";
350			break;
351		case 45:
352			message = "} expected after \\";
353			break;
354		case 46:
355			message = "First number exceeds second in \\{ \\}";
356			break;
357		case 49:
358			message = "[ ] imbalance";
359			break;
360		case 50:
361			message = "Regular expression too long";
362			break;
363		default:
364			message = "Unknown regexp error code!!";
365			break;
366	}
367	yyerror(message);
368	/* NOTREACHED */
369	return (0);
370}
371
372int
373yyerror(char *s)
374{
375	(void) write(2, "expr: ", 6);
376	(void) write(2, s, (unsigned) strlen(s));
377	(void) write(2, "\n", 1);
378	exit(2);
379	/* NOTREACHED */
380	return (0);
381}
382
383char *
384ltoa(long l)
385{
386	static char str[20];
387	char *sp;
388	int i;
389	int neg;
390
391	if(l == 0x80000000L)
392		return "-2147483648";
393	neg = 0;
394	if(l < 0)
395		++neg, l = -l;
396	sp = &str[20];
397	*--sp = '\0';
398	do {
399		i = l % 10;
400		*--sp = '0' + i;
401		l /= 10;
402	}
403	while(l);
404	if(neg)
405		*--sp = '-';
406	return sp;
407}
408
409int
410main(int argc, char **argv)
411{
412	Ac = argc;
413	Argi = 1;
414	Av = argv;
415	yyparse();
416	return (0);
417}
418