## root / intl / plural.y @ 1

History | View | Annotate | Download (7.18 KB)

1 |
%{ |
---|---|

2 |
/* Expression parsing for plural form selection. |

3 |
Copyright (C) 2000-2001, 2003 Free Software Foundation, Inc. |

4 |
Written by Ulrich Drepper <drepper@cygnus.com>, 2000. |

5 | |

6 |
This program is free software; you can redistribute it and/or modify it |

7 |
under the terms of the GNU Library General Public License as published |

8 |
by the Free Software Foundation; either version 2, or (at your option) |

9 |
any later version. |

10 | |

11 |
This program is distributed in the hope that it will be useful, |

12 |
but WITHOUT ANY WARRANTY; without even the implied warranty of |

13 |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |

14 |
Library General Public License for more details. |

15 | |

16 |
You should have received a copy of the GNU Library General Public |

17 |
License along with this program; if not, write to the Free Software |

18 |
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, |

19 |
USA. */ |

20 | |

21 |
/* The bison generated parser uses alloca. AIX 3 forces us to put this |

22 |
declaration at the beginning of the file. The declaration in bison's |

23 |
skeleton file comes too late. This must come before <config.h> |

24 |
because <config.h> may include arbitrary system headers. */ |

25 |
#if defined _AIX && !defined __GNUC__ |

26 |
#pragma alloca |

27 |
#endif |

28 | |

29 |
#ifdef HAVE_CONFIG_H |

30 |
# include <config.h> |

31 |
#endif |

32 | |

33 |
#include <stddef.h> |

34 |
#include <stdlib.h> |

35 |
#include "plural-exp.h" |

36 | |

37 |
/* The main function generated by the parser is called __gettextparse, |

38 |
but we want it to be called PLURAL_PARSE. */ |

39 |
#ifndef _LIBC |

40 |
# define __gettextparse PLURAL_PARSE |

41 |
#endif |

42 | |

43 |
#define YYLEX_PARAM &((struct parse_args *) arg)->cp |

44 |
#define YYPARSE_PARAM arg |

45 |
%} |

46 |
%pure_parser |

47 |
%expect 7 |

48 | |

49 |
%union { |

50 |
unsigned long int num; |

51 |
enum operator op; |

52 |
struct expression *exp; |

53 |
} |

54 | |

55 |
%{ |

56 |
/* Prototypes for local functions. */ |

57 |
static int yylex (YYSTYPE *lval, const char **pexp); |

58 |
static void yyerror (const char *str); |

59 | |

60 |
/* Allocation of expressions. */ |

61 | |

62 |
static struct expression * |

63 |
new_exp (int nargs, enum operator op, struct expression * const *args) |

64 |
{ |

65 |
int i; |

66 |
struct expression *newp; |

67 | |

68 |
/* If any of the argument could not be malloc'ed, just return NULL. */ |

69 |
for (i = nargs - 1; i >= 0; i--) |

70 |
if (args[i] == NULL) |

71 |
goto fail; |

72 | |

73 |
/* Allocate a new expression. */ |

74 |
newp = (struct expression *) malloc (sizeof (*newp)); |

75 |
if (newp != NULL) |

76 |
{ |

77 |
newp->nargs = nargs; |

78 |
newp->operation = op; |

79 |
for (i = nargs - 1; i >= 0; i--) |

80 |
newp->val.args[i] = args[i]; |

81 |
return newp; |

82 |
} |

83 | |

84 |
fail: |

85 |
for (i = nargs - 1; i >= 0; i--) |

86 |
FREE_EXPRESSION (args[i]); |

87 | |

88 |
return NULL; |

89 |
} |

90 | |

91 |
static inline struct expression * |

92 |
new_exp_0 (enum operator op) |

93 |
{ |

94 |
return new_exp (0, op, NULL); |

95 |
} |

96 | |

97 |
static inline struct expression * |

98 |
new_exp_1 (enum operator op, struct expression *right) |

99 |
{ |

100 |
struct expression *args[1]; |

101 | |

102 |
args[0] = right; |

103 |
return new_exp (1, op, args); |

104 |
} |

105 | |

106 |
static struct expression * |

107 |
new_exp_2 (enum operator op, struct expression *left, struct expression *right) |

108 |
{ |

109 |
struct expression *args[2]; |

110 | |

111 |
args[0] = left; |

112 |
args[1] = right; |

113 |
return new_exp (2, op, args); |

114 |
} |

115 | |

116 |
static inline struct expression * |

117 |
new_exp_3 (enum operator op, struct expression *bexp, |

118 |
struct expression *tbranch, struct expression *fbranch) |

119 |
{ |

120 |
struct expression *args[3]; |

121 | |

122 |
args[0] = bexp; |

123 |
args[1] = tbranch; |

124 |
args[2] = fbranch; |

125 |
return new_exp (3, op, args); |

126 |
} |

127 | |

128 |
%} |

129 | |

130 |
/* This declares that all operators have the same associativity and the |

131 |
precedence order as in C. See [Harbison, Steele: C, A Reference Manual]. |

132 |
There is no unary minus and no bitwise operators. |

133 |
Operators with the same syntactic behaviour have been merged into a single |

134 |
token, to save space in the array generated by bison. */ |

135 |
%right '?' /* ? */ |

136 |
%left '|' /* || */ |

137 |
%left '&' /* && */ |

138 |
%left EQUOP2 /* == != */ |

139 |
%left CMPOP2 /* < > <= >= */ |

140 |
%left ADDOP2 /* + - */ |

141 |
%left MULOP2 /* * / % */ |

142 |
%right '!' /* ! */ |

143 | |

144 |
%token <op> EQUOP2 CMPOP2 ADDOP2 MULOP2 |

145 |
%token <num> NUMBER |

146 |
%type <exp> exp |

147 | |

148 |
%% |

149 | |

150 |
start: exp |

151 |
{ |

152 |
if ($1 == NULL) |

153 |
YYABORT; |

154 |
((struct parse_args *) arg)->res = $1; |

155 |
} |

156 |
; |

157 | |

158 |
exp: exp '?' exp ':' exp |

159 |
{ |

160 |
$$ = new_exp_3 (qmop, $1, $3, $5); |

161 |
} |

162 |
| exp '|' exp |

163 |
{ |

164 |
$$ = new_exp_2 (lor, $1, $3); |

165 |
} |

166 |
| exp '&' exp |

167 |
{ |

168 |
$$ = new_exp_2 (land, $1, $3); |

169 |
} |

170 |
| exp EQUOP2 exp |

171 |
{ |

172 |
$$ = new_exp_2 ($2, $1, $3); |

173 |
} |

174 |
| exp CMPOP2 exp |

175 |
{ |

176 |
$$ = new_exp_2 ($2, $1, $3); |

177 |
} |

178 |
| exp ADDOP2 exp |

179 |
{ |

180 |
$$ = new_exp_2 ($2, $1, $3); |

181 |
} |

182 |
| exp MULOP2 exp |

183 |
{ |

184 |
$$ = new_exp_2 ($2, $1, $3); |

185 |
} |

186 |
| '!' exp |

187 |
{ |

188 |
$$ = new_exp_1 (lnot, $2); |

189 |
} |

190 |
| 'n' |

191 |
{ |

192 |
$$ = new_exp_0 (var); |

193 |
} |

194 |
| NUMBER |

195 |
{ |

196 |
if (($$ = new_exp_0 (num)) != NULL) |

197 |
$$->val.num = $1; |

198 |
} |

199 |
| '(' exp ')' |

200 |
{ |

201 |
$$ = $2; |

202 |
} |

203 |
; |

204 | |

205 |
%% |

206 | |

207 |
void |

208 |
internal_function |

209 |
FREE_EXPRESSION (struct expression *exp) |

210 |
{ |

211 |
if (exp == NULL) |

212 |
return; |

213 | |

214 |
/* Handle the recursive case. */ |

215 |
switch (exp->nargs) |

216 |
{ |

217 |
case 3: |

218 |
FREE_EXPRESSION (exp->val.args[2]); |

219 |
/* FALLTHROUGH */ |

220 |
case 2: |

221 |
FREE_EXPRESSION (exp->val.args[1]); |

222 |
/* FALLTHROUGH */ |

223 |
case 1: |

224 |
FREE_EXPRESSION (exp->val.args[0]); |

225 |
/* FALLTHROUGH */ |

226 |
default: |

227 |
break; |

228 |
} |

229 | |

230 |
free (exp); |

231 |
} |

232 | |

233 | |

234 |
static int |

235 |
yylex (YYSTYPE *lval, const char **pexp) |

236 |
{ |

237 |
const char *exp = *pexp; |

238 |
int result; |

239 | |

240 |
while (1) |

241 |
{ |

242 |
if (exp[0] == '\0') |

243 |
{ |

244 |
*pexp = exp; |

245 |
return YYEOF; |

246 |
} |

247 | |

248 |
if (exp[0] != ' ' && exp[0] != '\t') |

249 |
break; |

250 | |

251 |
++exp; |

252 |
} |

253 | |

254 |
result = *exp++; |

255 |
switch (result) |

256 |
{ |

257 |
case '0': case '1': case '2': case '3': case '4': |

258 |
case '5': case '6': case '7': case '8': case '9': |

259 |
{ |

260 |
unsigned long int n = result - '0'; |

261 |
while (exp[0] >= '0' && exp[0] <= '9') |

262 |
{ |

263 |
n *= 10; |

264 |
n += exp[0] - '0'; |

265 |
++exp; |

266 |
} |

267 |
lval->num = n; |

268 |
result = NUMBER; |

269 |
} |

270 |
break; |

271 | |

272 |
case '=': |

273 |
if (exp[0] == '=') |

274 |
{ |

275 |
++exp; |

276 |
lval->op = equal; |

277 |
result = EQUOP2; |

278 |
} |

279 |
else |

280 |
result = YYERRCODE; |

281 |
break; |

282 | |

283 |
case '!': |

284 |
if (exp[0] == '=') |

285 |
{ |

286 |
++exp; |

287 |
lval->op = not_equal; |

288 |
result = EQUOP2; |

289 |
} |

290 |
break; |

291 | |

292 |
case '&': |

293 |
case '|': |

294 |
if (exp[0] == result) |

295 |
++exp; |

296 |
else |

297 |
result = YYERRCODE; |

298 |
break; |

299 | |

300 |
case '<': |

301 |
if (exp[0] == '=') |

302 |
{ |

303 |
++exp; |

304 |
lval->op = less_or_equal; |

305 |
} |

306 |
else |

307 |
lval->op = less_than; |

308 |
result = CMPOP2; |

309 |
break; |

310 | |

311 |
case '>': |

312 |
if (exp[0] == '=') |

313 |
{ |

314 |
++exp; |

315 |
lval->op = greater_or_equal; |

316 |
} |

317 |
else |

318 |
lval->op = greater_than; |

319 |
result = CMPOP2; |

320 |
break; |

321 | |

322 |
case '*': |

323 |
lval->op = mult; |

324 |
result = MULOP2; |

325 |
break; |

326 | |

327 |
case '/': |

328 |
lval->op = divide; |

329 |
result = MULOP2; |

330 |
break; |

331 | |

332 |
case '%': |

333 |
lval->op = module; |

334 |
result = MULOP2; |

335 |
break; |

336 | |

337 |
case '+': |

338 |
lval->op = plus; |

339 |
result = ADDOP2; |

340 |
break; |

341 | |

342 |
case '-': |

343 |
lval->op = minus; |

344 |
result = ADDOP2; |

345 |
break; |

346 | |

347 |
case 'n': |

348 |
case '?': |

349 |
case ':': |

350 |
case '(': |

351 |
case ')': |

352 |
/* Nothing, just return the character. */ |

353 |
break; |

354 | |

355 |
case ';': |

356 |
case '\n': |

357 |
case '\0': |

358 |
/* Be safe and let the user call this function again. */ |

359 |
--exp; |

360 |
result = YYEOF; |

361 |
break; |

362 | |

363 |
default: |

364 |
result = YYERRCODE; |

365 |
#if YYDEBUG != 0 |

366 |
--exp; |

367 |
#endif |

368 |
break; |

369 |
} |

370 | |

371 |
*pexp = exp; |

372 | |

373 |
return result; |

374 |
} |

375 | |

376 | |

377 |
static void |

378 |
yyerror (const char *str) |

379 |
{ |

380 |
/* Do nothing. We don't print error messages here. */ |

381 |
} |