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