xref: /minix3/lib/libintl/plural_parser.c (revision 36dcc4a4a93f782ada76dce3d52fbeab0e063cf1)
1*36dcc4a4SLionel Sambuc /*	$NetBSD: plural_parser.c,v 1.2 2007/01/17 23:24:22 hubertf Exp $	*/
2*36dcc4a4SLionel Sambuc 
3*36dcc4a4SLionel Sambuc /*-
4*36dcc4a4SLionel Sambuc  * Copyright (c) 2005 Citrus Project,
5*36dcc4a4SLionel Sambuc  * All rights reserved.
6*36dcc4a4SLionel Sambuc  *
7*36dcc4a4SLionel Sambuc  * Redistribution and use in source and binary forms, with or without
8*36dcc4a4SLionel Sambuc  * modification, are permitted provided that the following conditions
9*36dcc4a4SLionel Sambuc  * are met:
10*36dcc4a4SLionel Sambuc  * 1. Redistributions of source code must retain the above copyright
11*36dcc4a4SLionel Sambuc  *    notice, this list of conditions and the following disclaimer.
12*36dcc4a4SLionel Sambuc  * 2. Redistributions in binary form must reproduce the above copyright
13*36dcc4a4SLionel Sambuc  *    notice, this list of conditions and the following disclaimer in the
14*36dcc4a4SLionel Sambuc  *    documentation and/or other materials provided with the distribution.
15*36dcc4a4SLionel Sambuc  *
16*36dcc4a4SLionel Sambuc  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17*36dcc4a4SLionel Sambuc  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18*36dcc4a4SLionel Sambuc  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19*36dcc4a4SLionel Sambuc  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20*36dcc4a4SLionel Sambuc  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21*36dcc4a4SLionel Sambuc  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22*36dcc4a4SLionel Sambuc  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23*36dcc4a4SLionel Sambuc  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24*36dcc4a4SLionel Sambuc  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25*36dcc4a4SLionel Sambuc  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26*36dcc4a4SLionel Sambuc  * SUCH DAMAGE.
27*36dcc4a4SLionel Sambuc  *
28*36dcc4a4SLionel Sambuc  */
29*36dcc4a4SLionel Sambuc 
30*36dcc4a4SLionel Sambuc #include <sys/cdefs.h>
31*36dcc4a4SLionel Sambuc __RCSID("$NetBSD: plural_parser.c,v 1.2 2007/01/17 23:24:22 hubertf Exp $");
32*36dcc4a4SLionel Sambuc 
33*36dcc4a4SLionel Sambuc #include <assert.h>
34*36dcc4a4SLionel Sambuc #include <stdio.h>
35*36dcc4a4SLionel Sambuc #include <stdlib.h>
36*36dcc4a4SLionel Sambuc #include <string.h>
37*36dcc4a4SLionel Sambuc #include <citrus/citrus_namespace.h>
38*36dcc4a4SLionel Sambuc #include <citrus/citrus_region.h>
39*36dcc4a4SLionel Sambuc #include <citrus/citrus_memstream.h>
40*36dcc4a4SLionel Sambuc #include <citrus/citrus_bcs.h>
41*36dcc4a4SLionel Sambuc #include "plural_parser.h"
42*36dcc4a4SLionel Sambuc 
43*36dcc4a4SLionel Sambuc #if defined(TEST_TOKENIZER) || defined(TEST_PARSER)
44*36dcc4a4SLionel Sambuc #define ALLOW_EMPTY
45*36dcc4a4SLionel Sambuc #define ALLOW_ARBITRARY_IDENTIFIER
46*36dcc4a4SLionel Sambuc #endif
47*36dcc4a4SLionel Sambuc 
48*36dcc4a4SLionel Sambuc #define MAX_LEN_ATOM		10
49*36dcc4a4SLionel Sambuc #define MAX_NUM_OPERANDS	3
50*36dcc4a4SLionel Sambuc 
51*36dcc4a4SLionel Sambuc #define T_EOF			EOF
52*36dcc4a4SLionel Sambuc #define T_NONE			0x100
53*36dcc4a4SLionel Sambuc #define T_LAND			0x101	/* && */
54*36dcc4a4SLionel Sambuc #define T_LOR			0x102	/* || */
55*36dcc4a4SLionel Sambuc #define T_EQUALITY		0x103	/* == or != */
56*36dcc4a4SLionel Sambuc #define T_RELATIONAL		0x104	/* <, >, <= or >= */
57*36dcc4a4SLionel Sambuc #define T_ADDITIVE		0x105	/* + or - */
58*36dcc4a4SLionel Sambuc #define T_MULTIPLICATIVE	0x106	/* *, / or % */
59*36dcc4a4SLionel Sambuc #define T_IDENTIFIER		0x200
60*36dcc4a4SLionel Sambuc #define T_CONSTANT		0x201
61*36dcc4a4SLionel Sambuc #define T_ILCHAR		0x300
62*36dcc4a4SLionel Sambuc #define T_TOOLONG		0x301
63*36dcc4a4SLionel Sambuc #define T_ILTOKEN		0x302
64*36dcc4a4SLionel Sambuc #define T_ILEND			0x303
65*36dcc4a4SLionel Sambuc #define T_NOMEM			0x304
66*36dcc4a4SLionel Sambuc #define T_NOTFOUND		0x305
67*36dcc4a4SLionel Sambuc #define T_ILPLURAL		0x306
68*36dcc4a4SLionel Sambuc #define T_IS_OPERATOR(t)	((t) < 0x200)
69*36dcc4a4SLionel Sambuc #define T_IS_ERROR(t)		((t) >= 0x300)
70*36dcc4a4SLionel Sambuc 
71*36dcc4a4SLionel Sambuc #define OP_EQ			('='+'=')
72*36dcc4a4SLionel Sambuc #define OP_NEQ			('!'+'=')
73*36dcc4a4SLionel Sambuc #define OP_LTEQ			('<'+'=')
74*36dcc4a4SLionel Sambuc #define OP_GTEQ			('>'+'=')
75*36dcc4a4SLionel Sambuc 
76*36dcc4a4SLionel Sambuc #define PLURAL_NUMBER_SYMBOL	"n"
77*36dcc4a4SLionel Sambuc #define NPLURALS_SYMBOL		"nplurals"
78*36dcc4a4SLionel Sambuc #define LEN_NPLURAL_SYMBOL	(sizeof (NPLURALS_SYMBOL) -1)
79*36dcc4a4SLionel Sambuc #define PLURAL_SYMBOL		"plural"
80*36dcc4a4SLionel Sambuc #define LEN_PLURAL_SYMBOL	(sizeof (PLURAL_SYMBOL) -1)
81*36dcc4a4SLionel Sambuc #define PLURAL_FORMS		"Plural-Forms:"
82*36dcc4a4SLionel Sambuc #define LEN_PLURAL_FORMS	(sizeof (PLURAL_FORMS) -1)
83*36dcc4a4SLionel Sambuc 
84*36dcc4a4SLionel Sambuc /* ----------------------------------------------------------------------
85*36dcc4a4SLionel Sambuc  * tokenizer part
86*36dcc4a4SLionel Sambuc  */
87*36dcc4a4SLionel Sambuc 
88*36dcc4a4SLionel Sambuc union token_data
89*36dcc4a4SLionel Sambuc {
90*36dcc4a4SLionel Sambuc 	unsigned long constant;
91*36dcc4a4SLionel Sambuc #ifdef ALLOW_ARBITRARY_IDENTIFIER
92*36dcc4a4SLionel Sambuc 	char identifier[MAX_LEN_ATOM+1];
93*36dcc4a4SLionel Sambuc #endif
94*36dcc4a4SLionel Sambuc 	char op;
95*36dcc4a4SLionel Sambuc };
96*36dcc4a4SLionel Sambuc 
97*36dcc4a4SLionel Sambuc struct tokenizer_context
98*36dcc4a4SLionel Sambuc {
99*36dcc4a4SLionel Sambuc 	struct _memstream memstream;
100*36dcc4a4SLionel Sambuc 	struct {
101*36dcc4a4SLionel Sambuc 		int token;
102*36dcc4a4SLionel Sambuc 		union token_data token_data;
103*36dcc4a4SLionel Sambuc 	} token0;
104*36dcc4a4SLionel Sambuc };
105*36dcc4a4SLionel Sambuc 
106*36dcc4a4SLionel Sambuc /* initialize a tokenizer context */
107*36dcc4a4SLionel Sambuc static void
init_tokenizer_context(struct tokenizer_context * tcx)108*36dcc4a4SLionel Sambuc init_tokenizer_context(struct tokenizer_context *tcx)
109*36dcc4a4SLionel Sambuc {
110*36dcc4a4SLionel Sambuc 	tcx->token0.token = T_NONE;
111*36dcc4a4SLionel Sambuc }
112*36dcc4a4SLionel Sambuc 
113*36dcc4a4SLionel Sambuc /* get an atom (identifier or constant) */
114*36dcc4a4SLionel Sambuc static int
tokenize_atom(struct tokenizer_context * tcx,union token_data * token_data)115*36dcc4a4SLionel Sambuc tokenize_atom(struct tokenizer_context *tcx, union token_data *token_data)
116*36dcc4a4SLionel Sambuc {
117*36dcc4a4SLionel Sambuc 	int ch, len;
118*36dcc4a4SLionel Sambuc 	char buf[MAX_LEN_ATOM+1];
119*36dcc4a4SLionel Sambuc 
120*36dcc4a4SLionel Sambuc 	len = 0;
121*36dcc4a4SLionel Sambuc 	while (/*CONSTCOND*/1) {
122*36dcc4a4SLionel Sambuc 		ch = _memstream_getc(&tcx->memstream);
123*36dcc4a4SLionel Sambuc 		if (!(_bcs_isalnum(ch) || ch == '_')) {
124*36dcc4a4SLionel Sambuc 			_memstream_ungetc(&tcx->memstream, ch);
125*36dcc4a4SLionel Sambuc 			break;
126*36dcc4a4SLionel Sambuc 		}
127*36dcc4a4SLionel Sambuc 		if (len == MAX_LEN_ATOM)
128*36dcc4a4SLionel Sambuc 			return T_TOOLONG;
129*36dcc4a4SLionel Sambuc 		buf[len++] = ch;
130*36dcc4a4SLionel Sambuc 	}
131*36dcc4a4SLionel Sambuc 	buf[len] = '\0';
132*36dcc4a4SLionel Sambuc 	if (len == 0)
133*36dcc4a4SLionel Sambuc 		return T_ILCHAR;
134*36dcc4a4SLionel Sambuc 
135*36dcc4a4SLionel Sambuc 	if (_bcs_isdigit((int)(unsigned char)buf[0])) {
136*36dcc4a4SLionel Sambuc 		unsigned long ul;
137*36dcc4a4SLionel Sambuc 		char *post;
138*36dcc4a4SLionel Sambuc 		ul = strtoul(buf, &post, 0);
139*36dcc4a4SLionel Sambuc 		if (buf+len != post)
140*36dcc4a4SLionel Sambuc 			return T_ILCHAR;
141*36dcc4a4SLionel Sambuc 		token_data->constant = ul;
142*36dcc4a4SLionel Sambuc 		return T_CONSTANT;
143*36dcc4a4SLionel Sambuc 	}
144*36dcc4a4SLionel Sambuc 
145*36dcc4a4SLionel Sambuc #ifdef ALLOW_ARBITRARY_IDENTIFIER
146*36dcc4a4SLionel Sambuc 	strcpy(token_data->identifier, buf);
147*36dcc4a4SLionel Sambuc 	return T_IDENTIFIER;
148*36dcc4a4SLionel Sambuc #else
149*36dcc4a4SLionel Sambuc 	if (!strcmp(buf, PLURAL_NUMBER_SYMBOL))
150*36dcc4a4SLionel Sambuc 		return T_IDENTIFIER;
151*36dcc4a4SLionel Sambuc 	return T_ILCHAR;
152*36dcc4a4SLionel Sambuc #endif
153*36dcc4a4SLionel Sambuc }
154*36dcc4a4SLionel Sambuc 
155*36dcc4a4SLionel Sambuc /* tokenizer main routine */
156*36dcc4a4SLionel Sambuc static int
tokenize(struct tokenizer_context * tcx,union token_data * token_data)157*36dcc4a4SLionel Sambuc tokenize(struct tokenizer_context *tcx, union token_data *token_data)
158*36dcc4a4SLionel Sambuc {
159*36dcc4a4SLionel Sambuc 	int ch, prevch;
160*36dcc4a4SLionel Sambuc 
161*36dcc4a4SLionel Sambuc retry:
162*36dcc4a4SLionel Sambuc 	ch = _memstream_getc(&tcx->memstream);
163*36dcc4a4SLionel Sambuc 	if (_bcs_isspace(ch))
164*36dcc4a4SLionel Sambuc 		goto retry;
165*36dcc4a4SLionel Sambuc 
166*36dcc4a4SLionel Sambuc 	switch (ch) {
167*36dcc4a4SLionel Sambuc 	case T_EOF:
168*36dcc4a4SLionel Sambuc 		return ch;
169*36dcc4a4SLionel Sambuc 	case '+': case '-':
170*36dcc4a4SLionel Sambuc 		token_data->op = ch;
171*36dcc4a4SLionel Sambuc 		return T_ADDITIVE;
172*36dcc4a4SLionel Sambuc 	case '*': case '/': case '%':
173*36dcc4a4SLionel Sambuc 		token_data->op = ch;
174*36dcc4a4SLionel Sambuc 		return T_MULTIPLICATIVE;
175*36dcc4a4SLionel Sambuc 	case '?': case ':': case '(': case ')':
176*36dcc4a4SLionel Sambuc 		token_data->op = ch;
177*36dcc4a4SLionel Sambuc 		return ch;
178*36dcc4a4SLionel Sambuc 	case '&': case '|':
179*36dcc4a4SLionel Sambuc 		prevch = ch;
180*36dcc4a4SLionel Sambuc 		ch = _memstream_getc(&tcx->memstream);
181*36dcc4a4SLionel Sambuc 		if (ch != prevch) {
182*36dcc4a4SLionel Sambuc 			_memstream_ungetc(&tcx->memstream, ch);
183*36dcc4a4SLionel Sambuc 			return T_ILCHAR;
184*36dcc4a4SLionel Sambuc 		}
185*36dcc4a4SLionel Sambuc 		token_data->op = ch;
186*36dcc4a4SLionel Sambuc 		switch (ch) {
187*36dcc4a4SLionel Sambuc 		case '&':
188*36dcc4a4SLionel Sambuc 			return T_LAND;
189*36dcc4a4SLionel Sambuc 		case '|':
190*36dcc4a4SLionel Sambuc 			return T_LOR;
191*36dcc4a4SLionel Sambuc 		}
192*36dcc4a4SLionel Sambuc 		/*NOTREACHED*/
193*36dcc4a4SLionel Sambuc 	case '=': case '!': case '<': case '>':
194*36dcc4a4SLionel Sambuc 		prevch = ch;
195*36dcc4a4SLionel Sambuc 		ch = _memstream_getc(&tcx->memstream);
196*36dcc4a4SLionel Sambuc 		if (ch != '=') {
197*36dcc4a4SLionel Sambuc 			_memstream_ungetc(&tcx->memstream, ch);
198*36dcc4a4SLionel Sambuc 			switch (prevch) {
199*36dcc4a4SLionel Sambuc 			case '=':
200*36dcc4a4SLionel Sambuc 				return T_ILCHAR;
201*36dcc4a4SLionel Sambuc 			case '!':
202*36dcc4a4SLionel Sambuc 				return '!';
203*36dcc4a4SLionel Sambuc 			case '<':
204*36dcc4a4SLionel Sambuc 			case '>':
205*36dcc4a4SLionel Sambuc 				token_data->op = prevch; /* OP_LT or OP_GT */
206*36dcc4a4SLionel Sambuc 				return T_RELATIONAL;
207*36dcc4a4SLionel Sambuc 			}
208*36dcc4a4SLionel Sambuc 		}
209*36dcc4a4SLionel Sambuc 		/* '==', '!=', '<=' or '>=' */
210*36dcc4a4SLionel Sambuc 		token_data->op = ch+prevch;
211*36dcc4a4SLionel Sambuc 		switch (prevch) {
212*36dcc4a4SLionel Sambuc 		case '=':
213*36dcc4a4SLionel Sambuc 		case '!':
214*36dcc4a4SLionel Sambuc 			return T_EQUALITY;
215*36dcc4a4SLionel Sambuc 		case '<':
216*36dcc4a4SLionel Sambuc 		case '>':
217*36dcc4a4SLionel Sambuc 			return T_RELATIONAL;
218*36dcc4a4SLionel Sambuc 		}
219*36dcc4a4SLionel Sambuc 		/*NOTREACHED*/
220*36dcc4a4SLionel Sambuc 	}
221*36dcc4a4SLionel Sambuc 
222*36dcc4a4SLionel Sambuc 	_memstream_ungetc(&tcx->memstream, ch);
223*36dcc4a4SLionel Sambuc 	return tokenize_atom(tcx, token_data);
224*36dcc4a4SLionel Sambuc }
225*36dcc4a4SLionel Sambuc 
226*36dcc4a4SLionel Sambuc /* get the next token */
227*36dcc4a4SLionel Sambuc static int
get_token(struct tokenizer_context * tcx,union token_data * token_data)228*36dcc4a4SLionel Sambuc get_token(struct tokenizer_context *tcx, union token_data *token_data)
229*36dcc4a4SLionel Sambuc {
230*36dcc4a4SLionel Sambuc 	if (tcx->token0.token != T_NONE) {
231*36dcc4a4SLionel Sambuc 		int token = tcx->token0.token;
232*36dcc4a4SLionel Sambuc 		tcx->token0.token = T_NONE;
233*36dcc4a4SLionel Sambuc 		*token_data = tcx->token0.token_data;
234*36dcc4a4SLionel Sambuc 		return token;
235*36dcc4a4SLionel Sambuc 	}
236*36dcc4a4SLionel Sambuc 	return tokenize(tcx, token_data);
237*36dcc4a4SLionel Sambuc }
238*36dcc4a4SLionel Sambuc 
239*36dcc4a4SLionel Sambuc /* push back the last token */
240*36dcc4a4SLionel Sambuc static void
unget_token(struct tokenizer_context * tcx,int token,union token_data * token_data)241*36dcc4a4SLionel Sambuc unget_token(struct tokenizer_context *tcx,
242*36dcc4a4SLionel Sambuc 	    int token, union token_data *token_data)
243*36dcc4a4SLionel Sambuc {
244*36dcc4a4SLionel Sambuc 	tcx->token0.token = token;
245*36dcc4a4SLionel Sambuc 	tcx->token0.token_data = *token_data;
246*36dcc4a4SLionel Sambuc }
247*36dcc4a4SLionel Sambuc 
248*36dcc4a4SLionel Sambuc #ifdef TEST_TOKENIZER
249*36dcc4a4SLionel Sambuc 
250*36dcc4a4SLionel Sambuc int
main(int argc,char ** argv)251*36dcc4a4SLionel Sambuc main(int argc, char **argv)
252*36dcc4a4SLionel Sambuc {
253*36dcc4a4SLionel Sambuc 	struct tokenizer_context tcx;
254*36dcc4a4SLionel Sambuc 	union token_data token_data;
255*36dcc4a4SLionel Sambuc 	int token;
256*36dcc4a4SLionel Sambuc 
257*36dcc4a4SLionel Sambuc 	if (argc != 2) {
258*36dcc4a4SLionel Sambuc 		fprintf(stderr, "usage: %s <expression>\n", argv[0]);
259*36dcc4a4SLionel Sambuc 		return EXIT_FAILURE;
260*36dcc4a4SLionel Sambuc 	}
261*36dcc4a4SLionel Sambuc 
262*36dcc4a4SLionel Sambuc 	init_tokenizer_context(&tcx);
263*36dcc4a4SLionel Sambuc 	_memstream_bind_ptr(&tcx.memstream, argv[1], strlen(argv[1]));
264*36dcc4a4SLionel Sambuc 
265*36dcc4a4SLionel Sambuc 	while (1) {
266*36dcc4a4SLionel Sambuc 		token = get_token(&tcx, &token_data);
267*36dcc4a4SLionel Sambuc 		switch (token) {
268*36dcc4a4SLionel Sambuc 		case T_EOF:
269*36dcc4a4SLionel Sambuc 			goto quit;
270*36dcc4a4SLionel Sambuc 		case T_ILCHAR:
271*36dcc4a4SLionel Sambuc 			printf("illegal character.\n");
272*36dcc4a4SLionel Sambuc 			goto quit;
273*36dcc4a4SLionel Sambuc 		case T_TOOLONG:
274*36dcc4a4SLionel Sambuc 			printf("too long atom.\n");
275*36dcc4a4SLionel Sambuc 			goto quit;
276*36dcc4a4SLionel Sambuc 		case T_CONSTANT:
277*36dcc4a4SLionel Sambuc 			printf("constant: %lu\n", token_data.constant);
278*36dcc4a4SLionel Sambuc 			break;
279*36dcc4a4SLionel Sambuc 		case T_IDENTIFIER:
280*36dcc4a4SLionel Sambuc 			printf("symbol: %s\n", token_data.identifier);
281*36dcc4a4SLionel Sambuc 			break;
282*36dcc4a4SLionel Sambuc 		default:
283*36dcc4a4SLionel Sambuc 			printf("operator: ");
284*36dcc4a4SLionel Sambuc 			switch (token) {
285*36dcc4a4SLionel Sambuc 			case T_LAND:
286*36dcc4a4SLionel Sambuc 				printf("&&\n");
287*36dcc4a4SLionel Sambuc 				break;
288*36dcc4a4SLionel Sambuc 			case T_LOR:
289*36dcc4a4SLionel Sambuc 				printf("||\n");
290*36dcc4a4SLionel Sambuc 				break;
291*36dcc4a4SLionel Sambuc 			case T_EQUALITY:
292*36dcc4a4SLionel Sambuc 				printf("%c=\n", token_data.op-'=');
293*36dcc4a4SLionel Sambuc 				break;
294*36dcc4a4SLionel Sambuc 			case T_RELATIONAL:
295*36dcc4a4SLionel Sambuc 				switch(token_data.op) {
296*36dcc4a4SLionel Sambuc 				case OP_LTEQ:
297*36dcc4a4SLionel Sambuc 				case OP_GTEQ:
298*36dcc4a4SLionel Sambuc 					printf("%c=\n", token_data.op-'=');
299*36dcc4a4SLionel Sambuc 					break;
300*36dcc4a4SLionel Sambuc 				default:
301*36dcc4a4SLionel Sambuc 					printf("%c\n", token_data.op);
302*36dcc4a4SLionel Sambuc 					break;
303*36dcc4a4SLionel Sambuc 				}
304*36dcc4a4SLionel Sambuc 				break;
305*36dcc4a4SLionel Sambuc 			case T_ADDITIVE:
306*36dcc4a4SLionel Sambuc 			case T_MULTIPLICATIVE:
307*36dcc4a4SLionel Sambuc 				printf("%c\n", token_data.op);
308*36dcc4a4SLionel Sambuc 				break;
309*36dcc4a4SLionel Sambuc 			default:
310*36dcc4a4SLionel Sambuc 				printf("operator: %c\n", token);
311*36dcc4a4SLionel Sambuc 			}
312*36dcc4a4SLionel Sambuc 		}
313*36dcc4a4SLionel Sambuc 	}
314*36dcc4a4SLionel Sambuc quit:
315*36dcc4a4SLionel Sambuc 	return 0;
316*36dcc4a4SLionel Sambuc }
317*36dcc4a4SLionel Sambuc #endif /* TEST_TOKENIZER */
318*36dcc4a4SLionel Sambuc 
319*36dcc4a4SLionel Sambuc 
320*36dcc4a4SLionel Sambuc /* ----------------------------------------------------------------------
321*36dcc4a4SLionel Sambuc  * parser part
322*36dcc4a4SLionel Sambuc  *
323*36dcc4a4SLionel Sambuc  * exp := cond
324*36dcc4a4SLionel Sambuc  *
325*36dcc4a4SLionel Sambuc  * cond := lor | lor '?' cond ':' cond
326*36dcc4a4SLionel Sambuc  *
327*36dcc4a4SLionel Sambuc  * lor := land ( '||' land )*
328*36dcc4a4SLionel Sambuc  *
329*36dcc4a4SLionel Sambuc  * land := equality ( '&&' equality )*
330*36dcc4a4SLionel Sambuc  *
331*36dcc4a4SLionel Sambuc  * equality := relational ( equalityops relational )*
332*36dcc4a4SLionel Sambuc  * equalityops := '==' | '!='
333*36dcc4a4SLionel Sambuc  *
334*36dcc4a4SLionel Sambuc  * relational := additive ( relationalops additive )*
335*36dcc4a4SLionel Sambuc  * relationalops := '<' | '>' | '<=' | '>='
336*36dcc4a4SLionel Sambuc  *
337*36dcc4a4SLionel Sambuc  * additive := multiplicative ( additiveops multiplicative )*
338*36dcc4a4SLionel Sambuc  * additiveops := '+' | '-'
339*36dcc4a4SLionel Sambuc  *
340*36dcc4a4SLionel Sambuc  * multiplicative := lnot ( multiplicativeops lnot )*
341*36dcc4a4SLionel Sambuc  * multiplicativeops := '*' | '/' | '%'
342*36dcc4a4SLionel Sambuc  *
343*36dcc4a4SLionel Sambuc  * lnot := '!' lnot | term
344*36dcc4a4SLionel Sambuc  *
345*36dcc4a4SLionel Sambuc  * term := literal | identifier | '(' exp ')'
346*36dcc4a4SLionel Sambuc  *
347*36dcc4a4SLionel Sambuc  */
348*36dcc4a4SLionel Sambuc 
349*36dcc4a4SLionel Sambuc #define T_ENSURE_OK(token, label)					      \
350*36dcc4a4SLionel Sambuc do {									      \
351*36dcc4a4SLionel Sambuc 	if (T_IS_ERROR(token))						      \
352*36dcc4a4SLionel Sambuc 		goto label;						      \
353*36dcc4a4SLionel Sambuc } while (/*CONSTCOND*/0)
354*36dcc4a4SLionel Sambuc #define T_ENSURE_SOMETHING(token, label)				      \
355*36dcc4a4SLionel Sambuc do {									      \
356*36dcc4a4SLionel Sambuc 	if ((token) == T_EOF) {						      \
357*36dcc4a4SLionel Sambuc 		token = T_ILEND;					      \
358*36dcc4a4SLionel Sambuc 		goto label;						      \
359*36dcc4a4SLionel Sambuc 	} else if (T_IS_ERROR(token))					      \
360*36dcc4a4SLionel Sambuc 		goto label;						      \
361*36dcc4a4SLionel Sambuc } while (/*CONSTCOND*/0)
362*36dcc4a4SLionel Sambuc 
363*36dcc4a4SLionel Sambuc #define parser_element	plural_element
364*36dcc4a4SLionel Sambuc 
365*36dcc4a4SLionel Sambuc struct parser_element;
366*36dcc4a4SLionel Sambuc struct parser_op
367*36dcc4a4SLionel Sambuc {
368*36dcc4a4SLionel Sambuc 	char op;
369*36dcc4a4SLionel Sambuc 	struct parser_element *operands[MAX_NUM_OPERANDS];
370*36dcc4a4SLionel Sambuc };
371*36dcc4a4SLionel Sambuc struct parser_element
372*36dcc4a4SLionel Sambuc {
373*36dcc4a4SLionel Sambuc 	int kind;
374*36dcc4a4SLionel Sambuc 	union
375*36dcc4a4SLionel Sambuc 	{
376*36dcc4a4SLionel Sambuc 		struct parser_op parser_op;
377*36dcc4a4SLionel Sambuc 		union token_data token_data;
378*36dcc4a4SLionel Sambuc 	} u;
379*36dcc4a4SLionel Sambuc };
380*36dcc4a4SLionel Sambuc 
381*36dcc4a4SLionel Sambuc struct parser_op2_transition
382*36dcc4a4SLionel Sambuc {
383*36dcc4a4SLionel Sambuc 	int					kind;
384*36dcc4a4SLionel Sambuc 	const struct parser_op2_transition	*next;
385*36dcc4a4SLionel Sambuc };
386*36dcc4a4SLionel Sambuc 
387*36dcc4a4SLionel Sambuc /* prototypes */
388*36dcc4a4SLionel Sambuc static int parse_cond(struct tokenizer_context *, struct parser_element *);
389*36dcc4a4SLionel Sambuc 
390*36dcc4a4SLionel Sambuc 
391*36dcc4a4SLionel Sambuc /* transition table for the 2-operand operators */
392*36dcc4a4SLionel Sambuc #define DEF_TR(t, k, n)							      \
393*36dcc4a4SLionel Sambuc static struct parser_op2_transition exp_tr_##t = {			      \
394*36dcc4a4SLionel Sambuc 	k, &exp_tr_##n							      \
395*36dcc4a4SLionel Sambuc }
396*36dcc4a4SLionel Sambuc #define DEF_TR0(t, k)							      \
397*36dcc4a4SLionel Sambuc static struct parser_op2_transition exp_tr_##t = {			      \
398*36dcc4a4SLionel Sambuc 	k, NULL /* expect lnot */					      \
399*36dcc4a4SLionel Sambuc }
400*36dcc4a4SLionel Sambuc 
401*36dcc4a4SLionel Sambuc DEF_TR0(multiplicative, T_MULTIPLICATIVE);
402*36dcc4a4SLionel Sambuc DEF_TR(additive, T_ADDITIVE, multiplicative);
403*36dcc4a4SLionel Sambuc DEF_TR(relational, T_RELATIONAL, additive);
404*36dcc4a4SLionel Sambuc DEF_TR(equality, T_EQUALITY, relational);
405*36dcc4a4SLionel Sambuc DEF_TR(land, T_LAND, equality);
406*36dcc4a4SLionel Sambuc DEF_TR(lor, T_LOR, land);
407*36dcc4a4SLionel Sambuc 
408*36dcc4a4SLionel Sambuc /* init a parser element structure */
409*36dcc4a4SLionel Sambuc static void
init_parser_element(struct parser_element * pe)410*36dcc4a4SLionel Sambuc init_parser_element(struct parser_element *pe)
411*36dcc4a4SLionel Sambuc {
412*36dcc4a4SLionel Sambuc 	int i;
413*36dcc4a4SLionel Sambuc 
414*36dcc4a4SLionel Sambuc 	pe->kind = T_NONE;
415*36dcc4a4SLionel Sambuc 	for (i=0; i<MAX_NUM_OPERANDS; i++)
416*36dcc4a4SLionel Sambuc 		pe->u.parser_op.operands[i] = NULL;
417*36dcc4a4SLionel Sambuc }
418*36dcc4a4SLionel Sambuc 
419*36dcc4a4SLionel Sambuc /* uninitialize a parser element structure with freeing children */
420*36dcc4a4SLionel Sambuc static void free_parser_element(struct parser_element *);
421*36dcc4a4SLionel Sambuc static void
uninit_parser_element(struct parser_element * pe)422*36dcc4a4SLionel Sambuc uninit_parser_element(struct parser_element *pe)
423*36dcc4a4SLionel Sambuc {
424*36dcc4a4SLionel Sambuc 	int i;
425*36dcc4a4SLionel Sambuc 
426*36dcc4a4SLionel Sambuc 	if (T_IS_OPERATOR(pe->kind))
427*36dcc4a4SLionel Sambuc 		for (i=0; i<MAX_NUM_OPERANDS; i++)
428*36dcc4a4SLionel Sambuc 			if (pe->u.parser_op.operands[i])
429*36dcc4a4SLionel Sambuc 				free_parser_element(
430*36dcc4a4SLionel Sambuc 					pe->u.parser_op.operands[i]);
431*36dcc4a4SLionel Sambuc }
432*36dcc4a4SLionel Sambuc 
433*36dcc4a4SLionel Sambuc /* free a parser element structure with freeing children */
434*36dcc4a4SLionel Sambuc static void
free_parser_element(struct parser_element * pe)435*36dcc4a4SLionel Sambuc free_parser_element(struct parser_element *pe)
436*36dcc4a4SLionel Sambuc {
437*36dcc4a4SLionel Sambuc 	if (pe) {
438*36dcc4a4SLionel Sambuc 		uninit_parser_element(pe);
439*36dcc4a4SLionel Sambuc 		free(pe);
440*36dcc4a4SLionel Sambuc 	}
441*36dcc4a4SLionel Sambuc }
442*36dcc4a4SLionel Sambuc 
443*36dcc4a4SLionel Sambuc 
444*36dcc4a4SLionel Sambuc /* copy a parser element structure shallowly */
445*36dcc4a4SLionel Sambuc static void
copy_parser_element(struct parser_element * dpe,const struct parser_element * spe)446*36dcc4a4SLionel Sambuc copy_parser_element(struct parser_element *dpe,
447*36dcc4a4SLionel Sambuc 		    const struct parser_element *spe)
448*36dcc4a4SLionel Sambuc {
449*36dcc4a4SLionel Sambuc 	memcpy(dpe, spe, sizeof *dpe);
450*36dcc4a4SLionel Sambuc }
451*36dcc4a4SLionel Sambuc 
452*36dcc4a4SLionel Sambuc /* duplicate a parser element structure shallowly */
453*36dcc4a4SLionel Sambuc static struct parser_element *
dup_parser_element(const struct parser_element * pe)454*36dcc4a4SLionel Sambuc dup_parser_element(const struct parser_element *pe)
455*36dcc4a4SLionel Sambuc {
456*36dcc4a4SLionel Sambuc 	struct parser_element *dpe = malloc(sizeof *dpe);
457*36dcc4a4SLionel Sambuc 	if (dpe)
458*36dcc4a4SLionel Sambuc 		copy_parser_element(dpe, pe);
459*36dcc4a4SLionel Sambuc 	return dpe;
460*36dcc4a4SLionel Sambuc }
461*36dcc4a4SLionel Sambuc 
462*36dcc4a4SLionel Sambuc /* term := identifier | constant | '(' exp ')' */
463*36dcc4a4SLionel Sambuc static int
parse_term(struct tokenizer_context * tcx,struct parser_element * pelem)464*36dcc4a4SLionel Sambuc parse_term(struct tokenizer_context *tcx, struct parser_element *pelem)
465*36dcc4a4SLionel Sambuc {
466*36dcc4a4SLionel Sambuc 	struct parser_element pe0;
467*36dcc4a4SLionel Sambuc 	int token;
468*36dcc4a4SLionel Sambuc 	union token_data token_data;
469*36dcc4a4SLionel Sambuc 
470*36dcc4a4SLionel Sambuc 	token = get_token(tcx, &token_data);
471*36dcc4a4SLionel Sambuc 	switch (token) {
472*36dcc4a4SLionel Sambuc 	case '(':
473*36dcc4a4SLionel Sambuc 		/* '(' exp ')' */
474*36dcc4a4SLionel Sambuc 		init_parser_element(&pe0);
475*36dcc4a4SLionel Sambuc 		/* expect exp */
476*36dcc4a4SLionel Sambuc 		token = parse_cond(tcx, &pe0);
477*36dcc4a4SLionel Sambuc 		T_ENSURE_OK(token, err);
478*36dcc4a4SLionel Sambuc 		/* expect ')' */
479*36dcc4a4SLionel Sambuc 		token = get_token(tcx, &token_data);
480*36dcc4a4SLionel Sambuc 		T_ENSURE_SOMETHING(token, err);
481*36dcc4a4SLionel Sambuc 		if (token != ')') {
482*36dcc4a4SLionel Sambuc 			unget_token(tcx, token, &token_data);
483*36dcc4a4SLionel Sambuc 			token = T_ILTOKEN;
484*36dcc4a4SLionel Sambuc 			goto err;
485*36dcc4a4SLionel Sambuc 		}
486*36dcc4a4SLionel Sambuc 		copy_parser_element(pelem, &pe0);
487*36dcc4a4SLionel Sambuc 		return token;
488*36dcc4a4SLionel Sambuc err:
489*36dcc4a4SLionel Sambuc 		uninit_parser_element(&pe0);
490*36dcc4a4SLionel Sambuc 		return token;
491*36dcc4a4SLionel Sambuc 	case T_IDENTIFIER:
492*36dcc4a4SLionel Sambuc 	case T_CONSTANT:
493*36dcc4a4SLionel Sambuc 		pelem->kind = token;
494*36dcc4a4SLionel Sambuc 		pelem->u.token_data = token_data;
495*36dcc4a4SLionel Sambuc 		return token;
496*36dcc4a4SLionel Sambuc 	case T_EOF:
497*36dcc4a4SLionel Sambuc 		return T_ILEND;
498*36dcc4a4SLionel Sambuc 	default:
499*36dcc4a4SLionel Sambuc 		return T_ILTOKEN;
500*36dcc4a4SLionel Sambuc 	}
501*36dcc4a4SLionel Sambuc }
502*36dcc4a4SLionel Sambuc 
503*36dcc4a4SLionel Sambuc /* lnot := '!' lnot | term */
504*36dcc4a4SLionel Sambuc static int
parse_lnot(struct tokenizer_context * tcx,struct parser_element * pelem)505*36dcc4a4SLionel Sambuc parse_lnot(struct tokenizer_context *tcx, struct parser_element *pelem)
506*36dcc4a4SLionel Sambuc {
507*36dcc4a4SLionel Sambuc 	struct parser_element pe0;
508*36dcc4a4SLionel Sambuc 	int token;
509*36dcc4a4SLionel Sambuc 	union token_data token_data;
510*36dcc4a4SLionel Sambuc 
511*36dcc4a4SLionel Sambuc 	init_parser_element(&pe0);
512*36dcc4a4SLionel Sambuc 
513*36dcc4a4SLionel Sambuc 	/* '!' or not */
514*36dcc4a4SLionel Sambuc 	token = get_token(tcx, &token_data);
515*36dcc4a4SLionel Sambuc 	if (token != '!') {
516*36dcc4a4SLionel Sambuc 		/* stop: term */
517*36dcc4a4SLionel Sambuc 		unget_token(tcx, token, &token_data);
518*36dcc4a4SLionel Sambuc 		return parse_term(tcx, pelem);
519*36dcc4a4SLionel Sambuc 	}
520*36dcc4a4SLionel Sambuc 
521*36dcc4a4SLionel Sambuc 	/* '!' term */
522*36dcc4a4SLionel Sambuc 	token = parse_lnot(tcx, &pe0);
523*36dcc4a4SLionel Sambuc 	T_ENSURE_OK(token, err);
524*36dcc4a4SLionel Sambuc 
525*36dcc4a4SLionel Sambuc 	pelem->kind = '!';
526*36dcc4a4SLionel Sambuc 	pelem->u.parser_op.operands[0] = dup_parser_element(&pe0);
527*36dcc4a4SLionel Sambuc 	return pelem->kind;
528*36dcc4a4SLionel Sambuc err:
529*36dcc4a4SLionel Sambuc 	uninit_parser_element(&pe0);
530*36dcc4a4SLionel Sambuc 	return token;
531*36dcc4a4SLionel Sambuc }
532*36dcc4a4SLionel Sambuc 
533*36dcc4a4SLionel Sambuc /* ext_op := ext_next ( op ext_next )* */
534*36dcc4a4SLionel Sambuc static int
parse_op2(struct tokenizer_context * tcx,struct parser_element * pelem,const struct parser_op2_transition * tr)535*36dcc4a4SLionel Sambuc parse_op2(struct tokenizer_context *tcx, struct parser_element *pelem,
536*36dcc4a4SLionel Sambuc 	  const struct parser_op2_transition *tr)
537*36dcc4a4SLionel Sambuc {
538*36dcc4a4SLionel Sambuc 	struct parser_element pe0, pe1, peop;
539*36dcc4a4SLionel Sambuc 	int token;
540*36dcc4a4SLionel Sambuc 	union token_data token_data;
541*36dcc4a4SLionel Sambuc 	char op;
542*36dcc4a4SLionel Sambuc 
543*36dcc4a4SLionel Sambuc 	/* special case: expect lnot */
544*36dcc4a4SLionel Sambuc 	if (tr == NULL)
545*36dcc4a4SLionel Sambuc 		return parse_lnot(tcx, pelem);
546*36dcc4a4SLionel Sambuc 
547*36dcc4a4SLionel Sambuc 	init_parser_element(&pe0);
548*36dcc4a4SLionel Sambuc 	init_parser_element(&pe1);
549*36dcc4a4SLionel Sambuc 	token = parse_op2(tcx, &pe0, tr->next);
550*36dcc4a4SLionel Sambuc 	T_ENSURE_OK(token, err);
551*36dcc4a4SLionel Sambuc 
552*36dcc4a4SLionel Sambuc 	while (/*CONSTCOND*/1) {
553*36dcc4a4SLionel Sambuc 		/* expect op or empty */
554*36dcc4a4SLionel Sambuc 		token = get_token(tcx, &token_data);
555*36dcc4a4SLionel Sambuc 		if (token != tr->kind) {
556*36dcc4a4SLionel Sambuc 			/* stop */
557*36dcc4a4SLionel Sambuc 			unget_token(tcx, token, &token_data);
558*36dcc4a4SLionel Sambuc 			copy_parser_element(pelem, &pe0);
559*36dcc4a4SLionel Sambuc 			break;
560*36dcc4a4SLionel Sambuc 		}
561*36dcc4a4SLionel Sambuc 		op = token_data.op;
562*36dcc4a4SLionel Sambuc 		/* right hand */
563*36dcc4a4SLionel Sambuc 		token = parse_op2(tcx, &pe1, tr->next);
564*36dcc4a4SLionel Sambuc 		T_ENSURE_OK(token, err);
565*36dcc4a4SLionel Sambuc 
566*36dcc4a4SLionel Sambuc 		init_parser_element(&peop);
567*36dcc4a4SLionel Sambuc 		peop.kind = tr->kind;
568*36dcc4a4SLionel Sambuc 		peop.u.parser_op.op = op;
569*36dcc4a4SLionel Sambuc 		peop.u.parser_op.operands[0] = dup_parser_element(&pe0);
570*36dcc4a4SLionel Sambuc 		init_parser_element(&pe0);
571*36dcc4a4SLionel Sambuc 		peop.u.parser_op.operands[1] = dup_parser_element(&pe1);
572*36dcc4a4SLionel Sambuc 		init_parser_element(&pe1);
573*36dcc4a4SLionel Sambuc 		copy_parser_element(&pe0, &peop);
574*36dcc4a4SLionel Sambuc 	}
575*36dcc4a4SLionel Sambuc 	return pelem->kind;
576*36dcc4a4SLionel Sambuc err:
577*36dcc4a4SLionel Sambuc 	uninit_parser_element(&pe1);
578*36dcc4a4SLionel Sambuc 	uninit_parser_element(&pe0);
579*36dcc4a4SLionel Sambuc 	return token;
580*36dcc4a4SLionel Sambuc }
581*36dcc4a4SLionel Sambuc 
582*36dcc4a4SLionel Sambuc /* cond := lor | lor '?' cond ':' cond */
583*36dcc4a4SLionel Sambuc static int
parse_cond(struct tokenizer_context * tcx,struct parser_element * pelem)584*36dcc4a4SLionel Sambuc parse_cond(struct tokenizer_context *tcx, struct parser_element *pelem)
585*36dcc4a4SLionel Sambuc {
586*36dcc4a4SLionel Sambuc 	struct parser_element pe0, pe1, pe2;
587*36dcc4a4SLionel Sambuc 	int token;
588*36dcc4a4SLionel Sambuc 	union token_data token_data;
589*36dcc4a4SLionel Sambuc 
590*36dcc4a4SLionel Sambuc 	init_parser_element(&pe0);
591*36dcc4a4SLionel Sambuc 	init_parser_element(&pe1);
592*36dcc4a4SLionel Sambuc 	init_parser_element(&pe2);
593*36dcc4a4SLionel Sambuc 
594*36dcc4a4SLionel Sambuc 	/* expect lor or empty */
595*36dcc4a4SLionel Sambuc 	token = parse_op2(tcx, &pe0, &exp_tr_lor);
596*36dcc4a4SLionel Sambuc 	T_ENSURE_OK(token, err);
597*36dcc4a4SLionel Sambuc 
598*36dcc4a4SLionel Sambuc 	/* '?' or not */
599*36dcc4a4SLionel Sambuc 	token = get_token(tcx, &token_data);
600*36dcc4a4SLionel Sambuc 	if (token != '?') {
601*36dcc4a4SLionel Sambuc 		/* stop: lor */
602*36dcc4a4SLionel Sambuc 		unget_token(tcx, token, &token_data);
603*36dcc4a4SLionel Sambuc 		copy_parser_element(pelem, &pe0);
604*36dcc4a4SLionel Sambuc 		return pe0.kind;
605*36dcc4a4SLionel Sambuc 	}
606*36dcc4a4SLionel Sambuc 
607*36dcc4a4SLionel Sambuc 	/* lor '?' cond ':' cond */
608*36dcc4a4SLionel Sambuc 	/* expect cond */
609*36dcc4a4SLionel Sambuc 	token = parse_cond(tcx, &pe1);
610*36dcc4a4SLionel Sambuc 	T_ENSURE_OK(token, err);
611*36dcc4a4SLionel Sambuc 
612*36dcc4a4SLionel Sambuc 	/* expect ':' */
613*36dcc4a4SLionel Sambuc 	token = get_token(tcx, &token_data);
614*36dcc4a4SLionel Sambuc 	T_ENSURE_OK(token, err);
615*36dcc4a4SLionel Sambuc 	if (token != ':') {
616*36dcc4a4SLionel Sambuc 		unget_token(tcx, token, &token_data);
617*36dcc4a4SLionel Sambuc 		token = T_ILTOKEN;
618*36dcc4a4SLionel Sambuc 		goto err;
619*36dcc4a4SLionel Sambuc 	}
620*36dcc4a4SLionel Sambuc 
621*36dcc4a4SLionel Sambuc 	/* expect cond */
622*36dcc4a4SLionel Sambuc 	token = parse_cond(tcx, &pe2);
623*36dcc4a4SLionel Sambuc 	T_ENSURE_OK(token, err);
624*36dcc4a4SLionel Sambuc 
625*36dcc4a4SLionel Sambuc 	pelem->kind = '?';
626*36dcc4a4SLionel Sambuc 	pelem->u.parser_op.operands[0] = dup_parser_element(&pe0);
627*36dcc4a4SLionel Sambuc 	pelem->u.parser_op.operands[1] = dup_parser_element(&pe1);
628*36dcc4a4SLionel Sambuc 	pelem->u.parser_op.operands[2] = dup_parser_element(&pe2);
629*36dcc4a4SLionel Sambuc 	return pelem->kind;
630*36dcc4a4SLionel Sambuc err:
631*36dcc4a4SLionel Sambuc 	uninit_parser_element(&pe2);
632*36dcc4a4SLionel Sambuc 	uninit_parser_element(&pe1);
633*36dcc4a4SLionel Sambuc 	uninit_parser_element(&pe0);
634*36dcc4a4SLionel Sambuc 	return token;
635*36dcc4a4SLionel Sambuc }
636*36dcc4a4SLionel Sambuc 
637*36dcc4a4SLionel Sambuc static int
parse_exp(struct tokenizer_context * tcx,struct parser_element * pelem)638*36dcc4a4SLionel Sambuc parse_exp(struct tokenizer_context *tcx, struct parser_element *pelem)
639*36dcc4a4SLionel Sambuc {
640*36dcc4a4SLionel Sambuc 	int token, token1;
641*36dcc4a4SLionel Sambuc 	union token_data token_data;
642*36dcc4a4SLionel Sambuc 
643*36dcc4a4SLionel Sambuc #ifdef ALLOW_EMPTY
644*36dcc4a4SLionel Sambuc 	/* empty check */
645*36dcc4a4SLionel Sambuc 	token = get_token(tcx, &token_data);
646*36dcc4a4SLionel Sambuc 	if (token == T_EOF)
647*36dcc4a4SLionel Sambuc 		return token;
648*36dcc4a4SLionel Sambuc 	unget_token(tcx, token, &token_data);
649*36dcc4a4SLionel Sambuc #endif
650*36dcc4a4SLionel Sambuc 
651*36dcc4a4SLionel Sambuc 	token = parse_cond(tcx, pelem);
652*36dcc4a4SLionel Sambuc 	if (!T_IS_ERROR(token)) {
653*36dcc4a4SLionel Sambuc 		/* termination check */
654*36dcc4a4SLionel Sambuc 		token1 = get_token(tcx, &token_data);
655*36dcc4a4SLionel Sambuc 		if (token1 == T_EOF)
656*36dcc4a4SLionel Sambuc 			return token;
657*36dcc4a4SLionel Sambuc 		else if (!T_IS_ERROR(token))
658*36dcc4a4SLionel Sambuc 			 unget_token(tcx, token1, &token_data);
659*36dcc4a4SLionel Sambuc 		return T_ILTOKEN;
660*36dcc4a4SLionel Sambuc 	}
661*36dcc4a4SLionel Sambuc 	return token;
662*36dcc4a4SLionel Sambuc }
663*36dcc4a4SLionel Sambuc 
664*36dcc4a4SLionel Sambuc 
665*36dcc4a4SLionel Sambuc #if defined(TEST_PARSER) || defined(TEST_PARSE_PLURAL)
666*36dcc4a4SLionel Sambuc #include <stdio.h>
667*36dcc4a4SLionel Sambuc 
668*36dcc4a4SLionel Sambuc static void dump_elem(struct parser_element *);
669*36dcc4a4SLionel Sambuc 
670*36dcc4a4SLionel Sambuc static void
dump_op2(struct parser_element * pelem)671*36dcc4a4SLionel Sambuc dump_op2(struct parser_element *pelem)
672*36dcc4a4SLionel Sambuc {
673*36dcc4a4SLionel Sambuc 	dump_elem(pelem->u.parser_op.operands[0]);
674*36dcc4a4SLionel Sambuc 	printf(" ");
675*36dcc4a4SLionel Sambuc 	dump_elem(pelem->u.parser_op.operands[1]);
676*36dcc4a4SLionel Sambuc 	printf(")");
677*36dcc4a4SLionel Sambuc }
678*36dcc4a4SLionel Sambuc 
679*36dcc4a4SLionel Sambuc static void
dump_op3(struct parser_element * pelem)680*36dcc4a4SLionel Sambuc dump_op3(struct parser_element *pelem)
681*36dcc4a4SLionel Sambuc {
682*36dcc4a4SLionel Sambuc 	dump_elem(pelem->u.parser_op.operands[0]);
683*36dcc4a4SLionel Sambuc 	printf(" ");
684*36dcc4a4SLionel Sambuc 	dump_elem(pelem->u.parser_op.operands[1]);
685*36dcc4a4SLionel Sambuc 	printf(" ");
686*36dcc4a4SLionel Sambuc 	dump_elem(pelem->u.parser_op.operands[2]);
687*36dcc4a4SLionel Sambuc 	printf(")");
688*36dcc4a4SLionel Sambuc }
689*36dcc4a4SLionel Sambuc 
690*36dcc4a4SLionel Sambuc static void
dump_elem(struct parser_element * pelem)691*36dcc4a4SLionel Sambuc dump_elem(struct parser_element *pelem)
692*36dcc4a4SLionel Sambuc {
693*36dcc4a4SLionel Sambuc 	switch (pelem->kind) {
694*36dcc4a4SLionel Sambuc 	case T_LAND:
695*36dcc4a4SLionel Sambuc 		printf("(&& ");
696*36dcc4a4SLionel Sambuc 		dump_op2(pelem);
697*36dcc4a4SLionel Sambuc 		break;
698*36dcc4a4SLionel Sambuc 	case T_LOR:
699*36dcc4a4SLionel Sambuc 		printf("(|| ");
700*36dcc4a4SLionel Sambuc 		dump_op2(pelem);
701*36dcc4a4SLionel Sambuc 		break;
702*36dcc4a4SLionel Sambuc 	case T_EQUALITY:
703*36dcc4a4SLionel Sambuc 		switch (pelem->u.parser_op.op) {
704*36dcc4a4SLionel Sambuc 		case OP_EQ:
705*36dcc4a4SLionel Sambuc 			printf("(== ");
706*36dcc4a4SLionel Sambuc 			break;
707*36dcc4a4SLionel Sambuc 		case OP_NEQ:
708*36dcc4a4SLionel Sambuc 			printf("(!= ");
709*36dcc4a4SLionel Sambuc 			break;
710*36dcc4a4SLionel Sambuc 		}
711*36dcc4a4SLionel Sambuc 		dump_op2(pelem);
712*36dcc4a4SLionel Sambuc 		break;
713*36dcc4a4SLionel Sambuc 	case T_RELATIONAL:
714*36dcc4a4SLionel Sambuc 		switch (pelem->u.parser_op.op) {
715*36dcc4a4SLionel Sambuc 		case '<':
716*36dcc4a4SLionel Sambuc 		case '>':
717*36dcc4a4SLionel Sambuc 			printf("(%c ", pelem->u.parser_op.op);
718*36dcc4a4SLionel Sambuc 			break;
719*36dcc4a4SLionel Sambuc 		case OP_LTEQ:
720*36dcc4a4SLionel Sambuc 		case OP_GTEQ:
721*36dcc4a4SLionel Sambuc 			printf("(%c= ", pelem->u.parser_op.op-'=');
722*36dcc4a4SLionel Sambuc 			break;
723*36dcc4a4SLionel Sambuc 		}
724*36dcc4a4SLionel Sambuc 		dump_op2(pelem);
725*36dcc4a4SLionel Sambuc 		break;
726*36dcc4a4SLionel Sambuc 	case T_ADDITIVE:
727*36dcc4a4SLionel Sambuc 	case T_MULTIPLICATIVE:
728*36dcc4a4SLionel Sambuc 		printf("(%c ", pelem->u.parser_op.op);
729*36dcc4a4SLionel Sambuc 		dump_op2(pelem);
730*36dcc4a4SLionel Sambuc 		break;
731*36dcc4a4SLionel Sambuc 	case '!':
732*36dcc4a4SLionel Sambuc 		printf("(! ");
733*36dcc4a4SLionel Sambuc 		dump_elem(pelem->u.parser_op.operands[0]);
734*36dcc4a4SLionel Sambuc 		printf(")");
735*36dcc4a4SLionel Sambuc 		break;
736*36dcc4a4SLionel Sambuc 	case '?':
737*36dcc4a4SLionel Sambuc 		printf("(? ");
738*36dcc4a4SLionel Sambuc 		dump_op3(pelem);
739*36dcc4a4SLionel Sambuc 		break;
740*36dcc4a4SLionel Sambuc 	case T_CONSTANT:
741*36dcc4a4SLionel Sambuc 		printf("%d", pelem->u.token_data.constant);
742*36dcc4a4SLionel Sambuc 		break;
743*36dcc4a4SLionel Sambuc 	case T_IDENTIFIER:
744*36dcc4a4SLionel Sambuc #ifdef ALLOW_ARBITRARY_IDENTIFIER
745*36dcc4a4SLionel Sambuc 		printf("%s", pelem->u.token_data.identifier);
746*36dcc4a4SLionel Sambuc #else
747*36dcc4a4SLionel Sambuc 		printf(PLURAL_NUMBER_SYMBOL);
748*36dcc4a4SLionel Sambuc #endif
749*36dcc4a4SLionel Sambuc 		break;
750*36dcc4a4SLionel Sambuc 	}
751*36dcc4a4SLionel Sambuc }
752*36dcc4a4SLionel Sambuc #endif
753*36dcc4a4SLionel Sambuc #ifdef TEST_PARSER
754*36dcc4a4SLionel Sambuc int
main(int argc,char ** argv)755*36dcc4a4SLionel Sambuc main(int argc, char **argv)
756*36dcc4a4SLionel Sambuc {
757*36dcc4a4SLionel Sambuc 	struct tokenizer_context tcx;
758*36dcc4a4SLionel Sambuc 	struct parser_element pelem;
759*36dcc4a4SLionel Sambuc 	int token;
760*36dcc4a4SLionel Sambuc 
761*36dcc4a4SLionel Sambuc 	if (argc != 2) {
762*36dcc4a4SLionel Sambuc 		fprintf(stderr, "usage: %s <expression>\n", argv[0]);
763*36dcc4a4SLionel Sambuc 		return EXIT_FAILURE;
764*36dcc4a4SLionel Sambuc 	}
765*36dcc4a4SLionel Sambuc 
766*36dcc4a4SLionel Sambuc 	init_tokenizer_context(&tcx);
767*36dcc4a4SLionel Sambuc 	_memstream_bind_ptr(&tcx.memstream, argv[1], strlen(argv[1]));
768*36dcc4a4SLionel Sambuc 
769*36dcc4a4SLionel Sambuc 	init_parser_element(&pelem);
770*36dcc4a4SLionel Sambuc 	token = parse_exp(&tcx, &pelem);
771*36dcc4a4SLionel Sambuc 
772*36dcc4a4SLionel Sambuc 	if (token == T_EOF)
773*36dcc4a4SLionel Sambuc 		printf("none");
774*36dcc4a4SLionel Sambuc 	else if (T_IS_ERROR(token))
775*36dcc4a4SLionel Sambuc 		printf("error: 0x%X", token);
776*36dcc4a4SLionel Sambuc 	else
777*36dcc4a4SLionel Sambuc 		dump_elem(&pelem);
778*36dcc4a4SLionel Sambuc 	printf("\n");
779*36dcc4a4SLionel Sambuc 
780*36dcc4a4SLionel Sambuc 	uninit_parser_element(&pelem);
781*36dcc4a4SLionel Sambuc 
782*36dcc4a4SLionel Sambuc 	return EXIT_SUCCESS;
783*36dcc4a4SLionel Sambuc }
784*36dcc4a4SLionel Sambuc #endif /* TEST_PARSER */
785*36dcc4a4SLionel Sambuc 
786*36dcc4a4SLionel Sambuc /* ----------------------------------------------------------------------
787*36dcc4a4SLionel Sambuc  * calcurate plural number
788*36dcc4a4SLionel Sambuc  */
789*36dcc4a4SLionel Sambuc static unsigned long
calculate_plural(const struct parser_element * pe,unsigned long n)790*36dcc4a4SLionel Sambuc calculate_plural(const struct parser_element *pe, unsigned long n)
791*36dcc4a4SLionel Sambuc {
792*36dcc4a4SLionel Sambuc 	unsigned long val0, val1;
793*36dcc4a4SLionel Sambuc 	switch (pe->kind) {
794*36dcc4a4SLionel Sambuc 	case T_IDENTIFIER:
795*36dcc4a4SLionel Sambuc 		return n;
796*36dcc4a4SLionel Sambuc 	case T_CONSTANT:
797*36dcc4a4SLionel Sambuc 		return pe->u.token_data.constant;
798*36dcc4a4SLionel Sambuc 	case '?':
799*36dcc4a4SLionel Sambuc 		val0 = calculate_plural(pe->u.parser_op.operands[0], n);
800*36dcc4a4SLionel Sambuc 		if (val0)
801*36dcc4a4SLionel Sambuc 			val1=calculate_plural(pe->u.parser_op.operands[1], n);
802*36dcc4a4SLionel Sambuc 		else
803*36dcc4a4SLionel Sambuc 			val1=calculate_plural(pe->u.parser_op.operands[2], n);
804*36dcc4a4SLionel Sambuc 		return val1;
805*36dcc4a4SLionel Sambuc 	case '!':
806*36dcc4a4SLionel Sambuc 		return !calculate_plural(pe->u.parser_op.operands[0], n);
807*36dcc4a4SLionel Sambuc 	case T_MULTIPLICATIVE:
808*36dcc4a4SLionel Sambuc 	case T_ADDITIVE:
809*36dcc4a4SLionel Sambuc 	case T_RELATIONAL:
810*36dcc4a4SLionel Sambuc 	case T_EQUALITY:
811*36dcc4a4SLionel Sambuc 	case T_LOR:
812*36dcc4a4SLionel Sambuc 	case T_LAND:
813*36dcc4a4SLionel Sambuc 		val0 = calculate_plural(pe->u.parser_op.operands[0], n);
814*36dcc4a4SLionel Sambuc 		val1 = calculate_plural(pe->u.parser_op.operands[1], n);
815*36dcc4a4SLionel Sambuc 		switch (pe->u.parser_op.op) {
816*36dcc4a4SLionel Sambuc 		case '*':
817*36dcc4a4SLionel Sambuc 			return val0*val1;
818*36dcc4a4SLionel Sambuc 		case '/':
819*36dcc4a4SLionel Sambuc 			return val0/val1;
820*36dcc4a4SLionel Sambuc 		case '%':
821*36dcc4a4SLionel Sambuc 			return val0%val1;
822*36dcc4a4SLionel Sambuc 		case '+':
823*36dcc4a4SLionel Sambuc 			return val0+val1;
824*36dcc4a4SLionel Sambuc 		case '-':
825*36dcc4a4SLionel Sambuc 			return val0-val1;
826*36dcc4a4SLionel Sambuc 		case '<':
827*36dcc4a4SLionel Sambuc 			return val0<val1;
828*36dcc4a4SLionel Sambuc 		case '>':
829*36dcc4a4SLionel Sambuc 			return val0>val1;
830*36dcc4a4SLionel Sambuc 		case OP_LTEQ:
831*36dcc4a4SLionel Sambuc 			return val0<=val1;
832*36dcc4a4SLionel Sambuc 		case OP_GTEQ:
833*36dcc4a4SLionel Sambuc 			return val0>=val1;
834*36dcc4a4SLionel Sambuc 		case OP_EQ:
835*36dcc4a4SLionel Sambuc 			return val0==val1;
836*36dcc4a4SLionel Sambuc 		case OP_NEQ:
837*36dcc4a4SLionel Sambuc 			return val0!=val1;
838*36dcc4a4SLionel Sambuc 		case '|':
839*36dcc4a4SLionel Sambuc 			return val0||val1;
840*36dcc4a4SLionel Sambuc 		case '&':
841*36dcc4a4SLionel Sambuc 			return val0&&val1;
842*36dcc4a4SLionel Sambuc 		}
843*36dcc4a4SLionel Sambuc 	}
844*36dcc4a4SLionel Sambuc 	return 0;
845*36dcc4a4SLionel Sambuc }
846*36dcc4a4SLionel Sambuc 
847*36dcc4a4SLionel Sambuc #ifdef TEST_CALC_PLURAL
848*36dcc4a4SLionel Sambuc #include <stdio.h>
849*36dcc4a4SLionel Sambuc 
850*36dcc4a4SLionel Sambuc int
main(int argc,char ** argv)851*36dcc4a4SLionel Sambuc main(int argc, char **argv)
852*36dcc4a4SLionel Sambuc {
853*36dcc4a4SLionel Sambuc 	struct tokenizer_context tcx;
854*36dcc4a4SLionel Sambuc 	struct parser_element pelem;
855*36dcc4a4SLionel Sambuc 	int token;
856*36dcc4a4SLionel Sambuc 
857*36dcc4a4SLionel Sambuc 	if (argc != 3) {
858*36dcc4a4SLionel Sambuc 		fprintf(stderr, "usage: %s <expression> <n>\n", argv[0]);
859*36dcc4a4SLionel Sambuc 		return EXIT_FAILURE;
860*36dcc4a4SLionel Sambuc 	}
861*36dcc4a4SLionel Sambuc 
862*36dcc4a4SLionel Sambuc 	init_tokenizer_context(&tcx);
863*36dcc4a4SLionel Sambuc 	_memstream_bind_ptr(&tcx.memstream, argv[1], strlen(argv[1]));
864*36dcc4a4SLionel Sambuc 
865*36dcc4a4SLionel Sambuc 	init_parser_element(&pelem);
866*36dcc4a4SLionel Sambuc 	token = parse_exp(&tcx, &pelem);
867*36dcc4a4SLionel Sambuc 
868*36dcc4a4SLionel Sambuc 	if (token == T_EOF)
869*36dcc4a4SLionel Sambuc 		printf("none");
870*36dcc4a4SLionel Sambuc 	else if (T_IS_ERROR(token))
871*36dcc4a4SLionel Sambuc 		printf("error: 0x%X", token);
872*36dcc4a4SLionel Sambuc 	else {
873*36dcc4a4SLionel Sambuc 		printf("plural = %lu",
874*36dcc4a4SLionel Sambuc 		       calculate_plural(&pelem, atoi(argv[2])));
875*36dcc4a4SLionel Sambuc 	}
876*36dcc4a4SLionel Sambuc 	printf("\n");
877*36dcc4a4SLionel Sambuc 
878*36dcc4a4SLionel Sambuc 	uninit_parser_element(&pelem);
879*36dcc4a4SLionel Sambuc 
880*36dcc4a4SLionel Sambuc 	return EXIT_SUCCESS;
881*36dcc4a4SLionel Sambuc }
882*36dcc4a4SLionel Sambuc #endif /* TEST_CALC_PLURAL */
883*36dcc4a4SLionel Sambuc 
884*36dcc4a4SLionel Sambuc 
885*36dcc4a4SLionel Sambuc /* ----------------------------------------------------------------------
886*36dcc4a4SLionel Sambuc  * parse plural forms
887*36dcc4a4SLionel Sambuc  */
888*36dcc4a4SLionel Sambuc 
889*36dcc4a4SLionel Sambuc static void
region_skip_ws(struct _region * r)890*36dcc4a4SLionel Sambuc region_skip_ws(struct _region *r)
891*36dcc4a4SLionel Sambuc {
892*36dcc4a4SLionel Sambuc 	const char *str = _region_head(r);
893*36dcc4a4SLionel Sambuc 	size_t len = _region_size(r);
894*36dcc4a4SLionel Sambuc 
895*36dcc4a4SLionel Sambuc 	str = _bcs_skip_ws_len(str, &len);
896*36dcc4a4SLionel Sambuc 	_region_init(r, __UNCONST(str), len);
897*36dcc4a4SLionel Sambuc }
898*36dcc4a4SLionel Sambuc 
899*36dcc4a4SLionel Sambuc static void
region_trunc_rws(struct _region * r)900*36dcc4a4SLionel Sambuc region_trunc_rws(struct _region *r)
901*36dcc4a4SLionel Sambuc {
902*36dcc4a4SLionel Sambuc 	const char *str = _region_head(r);
903*36dcc4a4SLionel Sambuc 	size_t len = _region_size(r);
904*36dcc4a4SLionel Sambuc 
905*36dcc4a4SLionel Sambuc 	_bcs_trunc_rws_len(str, &len);
906*36dcc4a4SLionel Sambuc 	_region_init(r, __UNCONST(str), len);
907*36dcc4a4SLionel Sambuc }
908*36dcc4a4SLionel Sambuc 
909*36dcc4a4SLionel Sambuc static int
region_check_prefix(struct _region * r,const char * pre,size_t prelen,int ignorecase)910*36dcc4a4SLionel Sambuc region_check_prefix(struct _region *r, const char *pre, size_t prelen,
911*36dcc4a4SLionel Sambuc 		    int ignorecase)
912*36dcc4a4SLionel Sambuc {
913*36dcc4a4SLionel Sambuc 	if (_region_size(r) < prelen)
914*36dcc4a4SLionel Sambuc 		return -1;
915*36dcc4a4SLionel Sambuc 
916*36dcc4a4SLionel Sambuc 	if (ignorecase) {
917*36dcc4a4SLionel Sambuc 		if (_bcs_strncasecmp(_region_head(r), pre, prelen))
918*36dcc4a4SLionel Sambuc 			return -1;
919*36dcc4a4SLionel Sambuc 	} else {
920*36dcc4a4SLionel Sambuc 		if (memcmp(_region_head(r), pre, prelen))
921*36dcc4a4SLionel Sambuc 			return -1;
922*36dcc4a4SLionel Sambuc 	}
923*36dcc4a4SLionel Sambuc 	return 0;
924*36dcc4a4SLionel Sambuc }
925*36dcc4a4SLionel Sambuc 
926*36dcc4a4SLionel Sambuc static int
cut_trailing_semicolon(struct _region * r)927*36dcc4a4SLionel Sambuc cut_trailing_semicolon(struct _region *r)
928*36dcc4a4SLionel Sambuc {
929*36dcc4a4SLionel Sambuc 
930*36dcc4a4SLionel Sambuc 	region_trunc_rws(r);
931*36dcc4a4SLionel Sambuc 	if (_region_size(r) == 0 || _region_peek8(r, _region_size(r)-1) != ';')
932*36dcc4a4SLionel Sambuc 		return -1;
933*36dcc4a4SLionel Sambuc 	_region_get_subregion(r, r, 0, _region_size(r)-1);
934*36dcc4a4SLionel Sambuc 	return 0;
935*36dcc4a4SLionel Sambuc }
936*36dcc4a4SLionel Sambuc 
937*36dcc4a4SLionel Sambuc static int
find_plural_forms(struct _region * r)938*36dcc4a4SLionel Sambuc find_plural_forms(struct _region *r)
939*36dcc4a4SLionel Sambuc {
940*36dcc4a4SLionel Sambuc 	struct _memstream ms;
941*36dcc4a4SLionel Sambuc 	struct _region rr;
942*36dcc4a4SLionel Sambuc 
943*36dcc4a4SLionel Sambuc 	_memstream_bind(&ms, r);
944*36dcc4a4SLionel Sambuc 
945*36dcc4a4SLionel Sambuc 	while (!_memstream_getln_region(&ms, &rr)) {
946*36dcc4a4SLionel Sambuc 		if (!region_check_prefix(&rr,
947*36dcc4a4SLionel Sambuc 					 PLURAL_FORMS, LEN_PLURAL_FORMS, 1)) {
948*36dcc4a4SLionel Sambuc 			_region_get_subregion(
949*36dcc4a4SLionel Sambuc 				r, &rr, LEN_PLURAL_FORMS,
950*36dcc4a4SLionel Sambuc 				_region_size(&rr)-LEN_PLURAL_FORMS);
951*36dcc4a4SLionel Sambuc 			region_skip_ws(r);
952*36dcc4a4SLionel Sambuc 			region_trunc_rws(r);
953*36dcc4a4SLionel Sambuc 			return 0;
954*36dcc4a4SLionel Sambuc 		}
955*36dcc4a4SLionel Sambuc 	}
956*36dcc4a4SLionel Sambuc 	return -1;
957*36dcc4a4SLionel Sambuc }
958*36dcc4a4SLionel Sambuc 
959*36dcc4a4SLionel Sambuc static int
skip_assignment(struct _region * r,const char * sym,size_t symlen)960*36dcc4a4SLionel Sambuc skip_assignment(struct _region *r, const char *sym, size_t symlen)
961*36dcc4a4SLionel Sambuc {
962*36dcc4a4SLionel Sambuc 	region_skip_ws(r);
963*36dcc4a4SLionel Sambuc 	if (region_check_prefix(r, sym, symlen, 0))
964*36dcc4a4SLionel Sambuc 		return -1;
965*36dcc4a4SLionel Sambuc 	_region_get_subregion(r, r, symlen, _region_size(r)-symlen);
966*36dcc4a4SLionel Sambuc 	region_skip_ws(r);
967*36dcc4a4SLionel Sambuc 	if (_region_size(r) == 0 || _region_peek8(r, 0) != '=')
968*36dcc4a4SLionel Sambuc 		return -1;
969*36dcc4a4SLionel Sambuc 	_region_get_subregion(r, r, 1, _region_size(r)-1);
970*36dcc4a4SLionel Sambuc 	region_skip_ws(r);
971*36dcc4a4SLionel Sambuc 	return 0;
972*36dcc4a4SLionel Sambuc }
973*36dcc4a4SLionel Sambuc 
974*36dcc4a4SLionel Sambuc static int
skip_nplurals(struct _region * r,unsigned long * rnp)975*36dcc4a4SLionel Sambuc skip_nplurals(struct _region *r, unsigned long *rnp)
976*36dcc4a4SLionel Sambuc {
977*36dcc4a4SLionel Sambuc 	unsigned long np;
978*36dcc4a4SLionel Sambuc 	char buf[MAX_LEN_ATOM+2], *endptr;
979*36dcc4a4SLionel Sambuc 	const char *endptrconst;
980*36dcc4a4SLionel Sambuc 	size_t ofs;
981*36dcc4a4SLionel Sambuc 
982*36dcc4a4SLionel Sambuc 	if (skip_assignment(r, NPLURALS_SYMBOL, LEN_NPLURAL_SYMBOL))
983*36dcc4a4SLionel Sambuc 		return -1;
984*36dcc4a4SLionel Sambuc 	if (_region_size(r) == 0 || !_bcs_isdigit(_region_peek8(r, 0)))
985*36dcc4a4SLionel Sambuc 		return -1;
986*36dcc4a4SLionel Sambuc 	strlcpy(buf, _region_head(r), sizeof (buf));
987*36dcc4a4SLionel Sambuc 	np = strtoul(buf, &endptr, 0);
988*36dcc4a4SLionel Sambuc 	endptrconst = _bcs_skip_ws(endptr);
989*36dcc4a4SLionel Sambuc 	if (*endptrconst != ';')
990*36dcc4a4SLionel Sambuc 		return -1;
991*36dcc4a4SLionel Sambuc 	ofs = endptrconst+1-buf;
992*36dcc4a4SLionel Sambuc 	if (_region_get_subregion(r, r, ofs, _region_size(r)-ofs))
993*36dcc4a4SLionel Sambuc 		return -1;
994*36dcc4a4SLionel Sambuc 	if (rnp)
995*36dcc4a4SLionel Sambuc 		*rnp = np;
996*36dcc4a4SLionel Sambuc 	return 0;
997*36dcc4a4SLionel Sambuc }
998*36dcc4a4SLionel Sambuc 
999*36dcc4a4SLionel Sambuc static int
parse_plural_body(struct _region * r,struct parser_element ** rpe)1000*36dcc4a4SLionel Sambuc parse_plural_body(struct _region *r, struct parser_element **rpe)
1001*36dcc4a4SLionel Sambuc {
1002*36dcc4a4SLionel Sambuc 	int token;
1003*36dcc4a4SLionel Sambuc 	struct tokenizer_context tcx;
1004*36dcc4a4SLionel Sambuc 	struct parser_element pelem, *ppe;
1005*36dcc4a4SLionel Sambuc 
1006*36dcc4a4SLionel Sambuc 	init_tokenizer_context(&tcx);
1007*36dcc4a4SLionel Sambuc 	_memstream_bind(&tcx.memstream, r);
1008*36dcc4a4SLionel Sambuc 
1009*36dcc4a4SLionel Sambuc 	init_parser_element(&pelem);
1010*36dcc4a4SLionel Sambuc 	token = parse_exp(&tcx, &pelem);
1011*36dcc4a4SLionel Sambuc 	if (T_IS_ERROR(token))
1012*36dcc4a4SLionel Sambuc 		return token;
1013*36dcc4a4SLionel Sambuc 
1014*36dcc4a4SLionel Sambuc 	ppe = dup_parser_element(&pelem);
1015*36dcc4a4SLionel Sambuc 	if (ppe == NULL) {
1016*36dcc4a4SLionel Sambuc 		uninit_parser_element(&pelem);
1017*36dcc4a4SLionel Sambuc 		return T_NOMEM;
1018*36dcc4a4SLionel Sambuc 	}
1019*36dcc4a4SLionel Sambuc 
1020*36dcc4a4SLionel Sambuc 	*rpe = ppe;
1021*36dcc4a4SLionel Sambuc 
1022*36dcc4a4SLionel Sambuc 	return 0;
1023*36dcc4a4SLionel Sambuc }
1024*36dcc4a4SLionel Sambuc 
1025*36dcc4a4SLionel Sambuc static int
parse_plural(struct parser_element ** rpe,unsigned long * rnp,const char * str,size_t len)1026*36dcc4a4SLionel Sambuc parse_plural(struct parser_element **rpe, unsigned long *rnp,
1027*36dcc4a4SLionel Sambuc 	     const char *str, size_t len)
1028*36dcc4a4SLionel Sambuc {
1029*36dcc4a4SLionel Sambuc 	struct _region r;
1030*36dcc4a4SLionel Sambuc 
1031*36dcc4a4SLionel Sambuc 	_region_init(&r, __UNCONST(str), len);
1032*36dcc4a4SLionel Sambuc 
1033*36dcc4a4SLionel Sambuc 	if (find_plural_forms(&r))
1034*36dcc4a4SLionel Sambuc 		return T_NOTFOUND;
1035*36dcc4a4SLionel Sambuc 	if (skip_nplurals(&r, rnp))
1036*36dcc4a4SLionel Sambuc 		return T_ILPLURAL;
1037*36dcc4a4SLionel Sambuc 	if (skip_assignment(&r, PLURAL_SYMBOL, LEN_PLURAL_SYMBOL))
1038*36dcc4a4SLionel Sambuc 		return T_ILPLURAL;
1039*36dcc4a4SLionel Sambuc 	if (cut_trailing_semicolon(&r))
1040*36dcc4a4SLionel Sambuc 		return T_ILPLURAL;
1041*36dcc4a4SLionel Sambuc 	return parse_plural_body(&r, rpe);
1042*36dcc4a4SLionel Sambuc }
1043*36dcc4a4SLionel Sambuc 
1044*36dcc4a4SLionel Sambuc #ifdef TEST_PARSE_PLURAL
1045*36dcc4a4SLionel Sambuc int
main(int argc,char ** argv)1046*36dcc4a4SLionel Sambuc main(int argc, char **argv)
1047*36dcc4a4SLionel Sambuc {
1048*36dcc4a4SLionel Sambuc 	int ret;
1049*36dcc4a4SLionel Sambuc 	struct parser_element *pelem;
1050*36dcc4a4SLionel Sambuc 	unsigned long np;
1051*36dcc4a4SLionel Sambuc 
1052*36dcc4a4SLionel Sambuc 	if (argc != 2 && argc != 3) {
1053*36dcc4a4SLionel Sambuc 		fprintf(stderr, "usage: %s <mime-header> [n]\n", argv[0]);
1054*36dcc4a4SLionel Sambuc 		return EXIT_FAILURE;
1055*36dcc4a4SLionel Sambuc 	}
1056*36dcc4a4SLionel Sambuc 
1057*36dcc4a4SLionel Sambuc 	ret = parse_plural(&pelem, &np, argv[1], strlen(argv[1]));
1058*36dcc4a4SLionel Sambuc 
1059*36dcc4a4SLionel Sambuc 	if (ret == T_EOF)
1060*36dcc4a4SLionel Sambuc 		printf("none");
1061*36dcc4a4SLionel Sambuc 	else if (T_IS_ERROR(ret))
1062*36dcc4a4SLionel Sambuc 		printf("error: 0x%X", ret);
1063*36dcc4a4SLionel Sambuc 	else {
1064*36dcc4a4SLionel Sambuc 		printf("syntax tree: ");
1065*36dcc4a4SLionel Sambuc 		dump_elem(pelem);
1066*36dcc4a4SLionel Sambuc 		printf("\nnplurals = %lu", np);
1067*36dcc4a4SLionel Sambuc 		if (argv[2])
1068*36dcc4a4SLionel Sambuc 			printf(", plural = %lu",
1069*36dcc4a4SLionel Sambuc 			       calculate_plural(pelem, atoi(argv[2])));
1070*36dcc4a4SLionel Sambuc 		free_parser_element(pelem);
1071*36dcc4a4SLionel Sambuc 	}
1072*36dcc4a4SLionel Sambuc 	printf("\n");
1073*36dcc4a4SLionel Sambuc 
1074*36dcc4a4SLionel Sambuc 
1075*36dcc4a4SLionel Sambuc 	return EXIT_SUCCESS;
1076*36dcc4a4SLionel Sambuc }
1077*36dcc4a4SLionel Sambuc #endif /* TEST_PARSE_PLURAL */
1078*36dcc4a4SLionel Sambuc 
1079*36dcc4a4SLionel Sambuc /*
1080*36dcc4a4SLionel Sambuc  * external interface
1081*36dcc4a4SLionel Sambuc  */
1082*36dcc4a4SLionel Sambuc 
1083*36dcc4a4SLionel Sambuc int
_gettext_parse_plural(struct gettext_plural ** rpe,unsigned long * rnp,const char * str,size_t len)1084*36dcc4a4SLionel Sambuc _gettext_parse_plural(struct gettext_plural **rpe, unsigned long *rnp,
1085*36dcc4a4SLionel Sambuc 		      const char *str, size_t len)
1086*36dcc4a4SLionel Sambuc {
1087*36dcc4a4SLionel Sambuc 	return parse_plural((struct parser_element **)rpe, rnp, str, len);
1088*36dcc4a4SLionel Sambuc }
1089*36dcc4a4SLionel Sambuc 
1090*36dcc4a4SLionel Sambuc unsigned long
_gettext_calculate_plural(const struct gettext_plural * pe,unsigned long n)1091*36dcc4a4SLionel Sambuc _gettext_calculate_plural(const struct gettext_plural *pe, unsigned long n)
1092*36dcc4a4SLionel Sambuc {
1093*36dcc4a4SLionel Sambuc 	return calculate_plural((void *)__UNCONST(pe), n);
1094*36dcc4a4SLionel Sambuc }
1095*36dcc4a4SLionel Sambuc 
1096*36dcc4a4SLionel Sambuc void
_gettext_free_plural(struct gettext_plural * pe)1097*36dcc4a4SLionel Sambuc _gettext_free_plural(struct gettext_plural *pe)
1098*36dcc4a4SLionel Sambuc {
1099*36dcc4a4SLionel Sambuc 	free_parser_element((void *)pe);
1100*36dcc4a4SLionel Sambuc }
1101*36dcc4a4SLionel Sambuc 
1102*36dcc4a4SLionel Sambuc #ifdef TEST_PLURAL
1103*36dcc4a4SLionel Sambuc #include <libintl.h>
1104*36dcc4a4SLionel Sambuc #include <locale.h>
1105*36dcc4a4SLionel Sambuc 
1106*36dcc4a4SLionel Sambuc #define PR(n)	printf("n=%d: \"%s\"\n", n, dngettext("test", "1", "2", n))
1107*36dcc4a4SLionel Sambuc 
1108*36dcc4a4SLionel Sambuc int
main(void)1109*36dcc4a4SLionel Sambuc main(void)
1110*36dcc4a4SLionel Sambuc {
1111*36dcc4a4SLionel Sambuc 	bindtextdomain("test", "."); /* ./LANG/LC_MESSAGES/test.mo */
1112*36dcc4a4SLionel Sambuc 	PR(1);
1113*36dcc4a4SLionel Sambuc 	PR(2);
1114*36dcc4a4SLionel Sambuc 	PR(3);
1115*36dcc4a4SLionel Sambuc 	PR(4);
1116*36dcc4a4SLionel Sambuc 
1117*36dcc4a4SLionel Sambuc 	return 0;
1118*36dcc4a4SLionel Sambuc }
1119*36dcc4a4SLionel Sambuc #endif
1120