xref: /reactos/sdk/tools/wpp/ppy.y (revision 1734f297)
1 /*
2  * Wrc preprocessor syntax analysis
3  *
4  * Copyright 1999-2000	Bertho A. Stultiens (BS)
5  *
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20  *
21  * History:
22  * 24-Apr-2000 BS	Restructured the lot to fit the new scanner
23  *			and reintegrate into the wine-tree.
24  * 01-Jan-2000 BS	FIXME: win16 preprocessor calculates with
25  *			16 bit ints and overflows...?
26  * 26-Dec-1999 BS	Started this file
27  *
28  */
29 
30 %{
31 #include "config.h"
32 #include "wine/port.h"
33 
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <stdarg.h>
37 #include <assert.h>
38 #include <ctype.h>
39 #include <string.h>
40 
41 #include "wpp_private.h"
42 
43 
44 #define UNARY_OP(r, v, OP)					\
45 	switch(v.type)						\
46 	{							\
47 	case cv_sint:	r.val.si  = OP v.val.si; break;		\
48 	case cv_uint:	r.val.ui  = OP v.val.ui; break;		\
49 	case cv_slong:	r.val.sl  = OP v.val.sl; break;		\
50 	case cv_ulong:	r.val.ul  = OP v.val.ul; break;		\
51 	case cv_sll:	r.val.sll = OP v.val.sll; break;	\
52 	case cv_ull:	r.val.ull = OP v.val.ull; break;	\
53 	}
54 
55 #define cv_signed(v)	((v.type & FLAG_SIGNED) != 0)
56 
57 #define BIN_OP_INT(r, v1, v2, OP)			\
58 	r.type = v1.type;				\
59 	if(cv_signed(v1) && cv_signed(v2))		\
60 		r.val.si = v1.val.si OP v2.val.si;	\
61 	else if(cv_signed(v1) && !cv_signed(v2))	\
62 		r.val.si = v1.val.si OP (signed) v2.val.ui; \
63 	else if(!cv_signed(v1) && cv_signed(v2))	\
64 		r.val.si = (signed) v1.val.ui OP v2.val.si; \
65 	else						\
66 		r.val.ui = v1.val.ui OP v2.val.ui;
67 
68 #define BIN_OP_LONG(r, v1, v2, OP)			\
69 	r.type = v1.type;				\
70 	if(cv_signed(v1) && cv_signed(v2))		\
71 		r.val.sl = v1.val.sl OP v2.val.sl;	\
72 	else if(cv_signed(v1) && !cv_signed(v2))	\
73 		r.val.sl = v1.val.sl OP (signed long) v2.val.ul; \
74 	else if(!cv_signed(v1) && cv_signed(v2))	\
75 		r.val.sl = (signed long) v1.val.ul OP v2.val.sl; \
76 	else						\
77 		r.val.ul = v1.val.ul OP v2.val.ul;
78 
79 #define BIN_OP_LONGLONG(r, v1, v2, OP)			\
80 	r.type = v1.type;				\
81 	if(cv_signed(v1) && cv_signed(v2))		\
82 		r.val.sll = v1.val.sll OP v2.val.sll;	\
83 	else if(cv_signed(v1) && !cv_signed(v2))	\
84 		r.val.sll = v1.val.sll OP (wrc_sll_t) v2.val.ull; \
85 	else if(!cv_signed(v1) && cv_signed(v2))	\
86 		r.val.sll = (wrc_sll_t) v1.val.ull OP v2.val.sll; \
87 	else						\
88 		r.val.ull = v1.val.ull OP v2.val.ull;
89 
90 #define BIN_OP(r, v1, v2, OP)						\
91 	switch(v1.type & SIZE_MASK)					\
92 	{								\
93 	case SIZE_INT:		BIN_OP_INT(r, v1, v2, OP); break;	\
94 	case SIZE_LONG:		BIN_OP_LONG(r, v1, v2, OP); break;	\
95 	case SIZE_LONGLONG:	BIN_OP_LONGLONG(r, v1, v2, OP); break;	\
96 	default: pp_internal_error(__FILE__, __LINE__, "Invalid type indicator (0x%04x)", v1.type);	\
97 	}
98 
99 
100 /*
101  * Prototypes
102  */
103 static int boolean(cval_t *v);
104 static void promote_equal_size(cval_t *v1, cval_t *v2);
105 static void cast_to_sint(cval_t *v);
106 static void cast_to_uint(cval_t *v);
107 static void cast_to_slong(cval_t *v);
108 static void cast_to_ulong(cval_t *v);
109 static void cast_to_sll(cval_t *v);
110 static void cast_to_ull(cval_t *v);
111 static marg_t *new_marg(char *str, def_arg_t type);
112 static marg_t *add_new_marg(char *str, def_arg_t type);
113 static int marg_index(char *id);
114 static mtext_t *new_mtext(char *str, int idx, def_exp_t type);
115 static mtext_t *combine_mtext(mtext_t *tail, mtext_t *mtp);
116 static char *merge_text(char *s1, char *s2);
117 
118 /*
119  * Local variables
120  */
121 static marg_t **macro_args;	/* Macro parameters array while parsing */
122 static int	nmacro_args;
123 
124 %}
125 
126 %union{
127 	int		sint;
128 	unsigned int	uint;
129 	long		slong;
130 	unsigned long	ulong;
131 	wrc_sll_t	sll;
132 	wrc_ull_t	ull;
133 	int		*iptr;
134 	char		*cptr;
135 	cval_t		cval;
136 	marg_t		*marg;
137 	mtext_t		*mtext;
138 }
139 
140 %token tRCINCLUDE
141 %token tIF tIFDEF tIFNDEF tELSE tELIF tENDIF tDEFINED tNL
142 %token tINCLUDE tLINE tGCCLINE tERROR tWARNING tPRAGMA tPPIDENT
143 %token tUNDEF tMACROEND tCONCAT tELIPSIS tSTRINGIZE
144 %token <cptr> tIDENT tLITERAL tMACRO tDEFINE
145 %token <cptr> tDQSTRING tSQSTRING tIQSTRING
146 %token <uint> tUINT
147 %token <sint> tSINT
148 %token <ulong> tULONG
149 %token <slong> tSLONG
150 %token <ull> tULONGLONG
151 %token <sll> tSLONGLONG
152 %token <cptr> tRCINCLUDEPATH
153 
154 %right '?' ':'
155 %left tLOGOR
156 %left tLOGAND
157 %left '|'
158 %left '^'
159 %left '&'
160 %left tEQ tNE
161 %left '<' tLTE '>' tGTE
162 %left tLSHIFT tRSHIFT
163 %left '+' '-'
164 %left '*' '/'
165 %right '~' '!'
166 
167 %type <cval>	pp_expr
168 %type <marg>	emargs margs
169 %type <mtext>	opt_mtexts mtexts mtext
170 %type <sint>	allmargs
171 %type <cptr>	opt_text text
172 
173 /*
174  **************************************************************************
175  * The parser starts here
176  **************************************************************************
177  */
178 
179 %%
180 
181 pp_file	: /* Empty */
182 	| pp_file preprocessor
183 	;
184 
185 preprocessor
186 	: tINCLUDE tDQSTRING tNL	{ pp_do_include($2, 1); }
187 	| tINCLUDE tIQSTRING tNL	{ pp_do_include($2, 0); }
188 	| tIF pp_expr tNL	{ pp_next_if_state(boolean(&$2)); }
189 	| tIFDEF tIDENT tNL	{ pp_next_if_state(pplookup($2) != NULL); free($2); }
190 	| tIFNDEF tIDENT tNL	{
191 		int t = pplookup($2) == NULL;
192 		if(pp_incl_state.state == 0 && t && !pp_incl_state.seen_junk)
193 		{
194 			pp_incl_state.state	= 1;
195 			pp_incl_state.ppp	= $2;
196 			pp_incl_state.ifdepth	= pp_get_if_depth();
197 		}
198 		else if(pp_incl_state.state != 1)
199 		{
200 			pp_incl_state.state = -1;
201 			free($2);
202 		}
203 		else
204 			free($2);
205 		pp_next_if_state(t);
206 		if(pp_status.debug)
207 			fprintf(stderr, "tIFNDEF: %s:%d: include_state=%d, include_ppp='%s', include_ifdepth=%d\n",
208                                 pp_status.input, pp_status.line_number, pp_incl_state.state, pp_incl_state.ppp, pp_incl_state.ifdepth);
209 		}
210 	| tELIF pp_expr tNL	{
211 		pp_if_state_t s = pp_pop_if();
212 		switch(s)
213 		{
214 		case if_true:
215 		case if_elif:
216 			pp_push_if(if_elif);
217 			break;
218 		case if_false:
219 			pp_push_if(boolean(&$2) ? if_true : if_false);
220 			break;
221 		case if_ignore:
222 			pp_push_if(if_ignore);
223 			break;
224 		case if_elsetrue:
225 		case if_elsefalse:
226 			ppy_error("#elif cannot follow #else");
227 			break;
228 		case if_error:
229 			break;
230 		default:
231 			pp_internal_error(__FILE__, __LINE__, "Invalid pp_if_state (%d) in #elif directive", s);
232 		}
233 		}
234 	| tELSE tNL		{
235 		pp_if_state_t s = pp_pop_if();
236 		switch(s)
237 		{
238 		case if_true:
239 			pp_push_if(if_elsefalse);
240 			break;
241 		case if_elif:
242 			pp_push_if(if_elif);
243 			break;
244 		case if_false:
245 			pp_push_if(if_elsetrue);
246 			break;
247 		case if_ignore:
248 			pp_push_if(if_ignore);
249 			break;
250 		case if_elsetrue:
251 		case if_elsefalse:
252 			ppy_error("#else clause already defined");
253 			break;
254 		case if_error:
255 			break;
256 		default:
257 			pp_internal_error(__FILE__, __LINE__, "Invalid pp_if_state (%d) in #else directive", s);
258 		}
259 		}
260 	| tENDIF tNL		{
261 		if(pp_pop_if() != if_error)
262 		{
263 			if(pp_incl_state.ifdepth == pp_get_if_depth() && pp_incl_state.state == 1)
264 			{
265 				pp_incl_state.state = 2;
266 				pp_incl_state.seen_junk = 0;
267 			}
268 			else if(pp_incl_state.state != 1)
269 			{
270 				pp_incl_state.state = -1;
271 			}
272 			if(pp_status.debug)
273 				fprintf(stderr, "tENDIF: %s:%d: include_state=%d, include_ppp='%s', include_ifdepth=%d\n",
274 					pp_status.input, pp_status.line_number, pp_incl_state.state, pp_incl_state.ppp, pp_incl_state.ifdepth);
275 		}
276 		}
277 	| tUNDEF tIDENT tNL	{ pp_del_define($2); free($2); }
278 	| tDEFINE opt_text tNL	{ pp_add_define($1, $2); free($1); free($2); }
279 	| tMACRO res_arg allmargs tMACROEND opt_mtexts tNL	{
280 		pp_add_macro($1, macro_args, nmacro_args, $5);
281 		}
282 	| tLINE tSINT tDQSTRING	tNL	{ if($3) pp_writestring("# %d %s\n", $2 , $3); free($3); }
283 	| tGCCLINE tSINT tDQSTRING tNL	{ if($3) pp_writestring("# %d %s\n", $2 , $3); free($3); }
284 	| tGCCLINE tSINT tDQSTRING tSINT tNL
285 		{ if($3) pp_writestring("# %d %s %d\n", $2, $3, $4); free($3); }
286 	| tGCCLINE tSINT tDQSTRING tSINT tSINT tNL
287 		{ if($3) pp_writestring("# %d %s %d %d\n", $2 ,$3, $4, $5); free($3); }
288 	| tGCCLINE tSINT tDQSTRING tSINT tSINT tSINT  tNL
289 		{ if($3) pp_writestring("# %d %s %d %d %d\n", $2 ,$3 ,$4 ,$5, $6); free($3); }
290 	| tGCCLINE tSINT tDQSTRING tSINT tSINT tSINT tSINT tNL
291 		{ if($3) pp_writestring("# %d %s %d %d %d %d\n", $2 ,$3 ,$4 ,$5, $6, $7); free($3); }
292 	| tGCCLINE tNL		/* The null-token */
293 	| tERROR opt_text tNL	{ ppy_error("#error directive: '%s'", $2); free($2); }
294 	| tWARNING opt_text tNL	{ ppy_warning("#warning directive: '%s'", $2); free($2); }
295 	| tPRAGMA opt_text tNL	{ pp_writestring("#pragma %s\n", $2 ? $2 : ""); free($2); }
296 	| tPPIDENT opt_text tNL	{ if(pp_status.pedantic) ppy_warning("#ident ignored (arg: '%s')", $2); free($2); }
297         | tRCINCLUDE tRCINCLUDEPATH {
298                 if($2)
299                 {
300                         int nl=strlen($2) +3;
301                         char *fn=pp_xmalloc(nl);
302                         if(fn)
303                         {
304                                 sprintf(fn,"\"%s\"",$2);
305                                 pp_do_include(fn,1);
306                         }
307                         free($2);
308                 }
309 	}
310 	| tRCINCLUDE tDQSTRING {
311 		pp_do_include($2,1);
312 	}
313 	/*| tNL*/
314 	;
315 
316 opt_text: /* Empty */	{ $$ = NULL; }
317 	| text		{ $$ = $1; }
318 	;
319 
320 text	: tLITERAL		{ $$ = $1; }
321 	| tDQSTRING		{ $$ = $1; }
322 	| tSQSTRING		{ $$ = $1; }
323 	| text tLITERAL		{ $$ = merge_text($1, $2); }
324 	| text tDQSTRING	{ $$ = merge_text($1, $2); }
325 	| text tSQSTRING	{ $$ = merge_text($1, $2); }
326 	;
327 
328 res_arg	: /* Empty */	{ macro_args = NULL; nmacro_args = 0; }
329 	;
330 
331 allmargs: /* Empty */		{ $$ = 0; macro_args = NULL; nmacro_args = 0; }
332 	| emargs		{ $$ = nmacro_args; }
333 	;
334 
335 emargs	: margs			{ $$ = $1; }
336 	| margs ',' tELIPSIS	{ $$ = add_new_marg(NULL, arg_list); nmacro_args *= -1; }
337 	;
338 
339 margs	: margs ',' tIDENT	{ $$ = add_new_marg($3, arg_single); }
340 	| tIDENT		{ $$ = add_new_marg($1, arg_single); }
341 	;
342 
343 opt_mtexts
344 	: /* Empty */	{ $$ = NULL; }
345 	| mtexts	{
346 		for($$ = $1; $$ && $$->prev; $$ = $$->prev)
347 			;
348 		}
349 	;
350 
351 mtexts	: mtext		{ $$ = $1; }
352 	| mtexts mtext	{ $$ = combine_mtext($1, $2); }
353 	;
354 
355 mtext	: tLITERAL	{ $$ = new_mtext($1, 0, exp_text); }
356 	| tDQSTRING	{ $$ = new_mtext($1, 0, exp_text); }
357 	| tSQSTRING	{ $$ = new_mtext($1, 0, exp_text); }
358 	| tCONCAT	{ $$ = new_mtext(NULL, 0, exp_concat); }
359 	| tSTRINGIZE tIDENT	{
360 		int mat = marg_index($2);
361 		if(mat < 0)
362 			ppy_error("Stringification identifier must be an argument parameter");
363 		else
364 			$$ = new_mtext(NULL, mat, exp_stringize);
365 		}
366 	| tIDENT	{
367 		int mat = marg_index($1);
368 		if(mat >= 0)
369 			$$ = new_mtext(NULL, mat, exp_subst);
370 		else if($1)
371 			$$ = new_mtext($1, 0, exp_text);
372 		}
373 	;
374 
375 pp_expr	: tSINT				{ $$.type = cv_sint;  $$.val.si = $1; }
376 	| tUINT				{ $$.type = cv_uint;  $$.val.ui = $1; }
377 	| tSLONG			{ $$.type = cv_slong; $$.val.sl = $1; }
378 	| tULONG			{ $$.type = cv_ulong; $$.val.ul = $1; }
379 	| tSLONGLONG			{ $$.type = cv_sll;   $$.val.sll = $1; }
380 	| tULONGLONG			{ $$.type = cv_ull;   $$.val.ull = $1; }
381 	| tDEFINED tIDENT		{ $$.type = cv_sint;  $$.val.si = pplookup($2) != NULL; }
382 	| tDEFINED '(' tIDENT ')'	{ $$.type = cv_sint;  $$.val.si = pplookup($3) != NULL; }
383 	| tIDENT			{ $$.type = cv_sint;  $$.val.si = 0; }
384 	| pp_expr tLOGOR pp_expr	{ $$.type = cv_sint; $$.val.si = boolean(&$1) || boolean(&$3); }
385 	| pp_expr tLOGAND pp_expr	{ $$.type = cv_sint; $$.val.si = boolean(&$1) && boolean(&$3); }
386 	| pp_expr tEQ pp_expr		{ promote_equal_size(&$1, &$3); BIN_OP($$, $1, $3, ==); }
387 	| pp_expr tNE pp_expr		{ promote_equal_size(&$1, &$3); BIN_OP($$, $1, $3, !=); }
388 	| pp_expr '<' pp_expr		{ promote_equal_size(&$1, &$3); BIN_OP($$, $1, $3,  <); }
389 	| pp_expr '>' pp_expr		{ promote_equal_size(&$1, &$3); BIN_OP($$, $1, $3,  >); }
390 	| pp_expr tLTE pp_expr		{ promote_equal_size(&$1, &$3); BIN_OP($$, $1, $3, <=); }
391 	| pp_expr tGTE pp_expr		{ promote_equal_size(&$1, &$3); BIN_OP($$, $1, $3, >=); }
392 	| pp_expr '+' pp_expr		{ promote_equal_size(&$1, &$3); BIN_OP($$, $1, $3,  +); }
393 	| pp_expr '-' pp_expr		{ promote_equal_size(&$1, &$3); BIN_OP($$, $1, $3,  -); }
394 	| pp_expr '^' pp_expr		{ promote_equal_size(&$1, &$3); BIN_OP($$, $1, $3,  ^); }
395 	| pp_expr '&' pp_expr		{ promote_equal_size(&$1, &$3); BIN_OP($$, $1, $3,  &); }
396 	| pp_expr '|' pp_expr		{ promote_equal_size(&$1, &$3); BIN_OP($$, $1, $3,  |); }
397 	| pp_expr '*' pp_expr		{ promote_equal_size(&$1, &$3); BIN_OP($$, $1, $3,  *); }
398 	| pp_expr '/' pp_expr		{ promote_equal_size(&$1, &$3); BIN_OP($$, $1, $3,  /); }
399 	| pp_expr tLSHIFT pp_expr	{ promote_equal_size(&$1, &$3); BIN_OP($$, $1, $3, <<); }
400 	| pp_expr tRSHIFT pp_expr	{ promote_equal_size(&$1, &$3); BIN_OP($$, $1, $3, >>); }
401 	| '+' pp_expr			{ $$ =  $2; }
402 	| '-' pp_expr			{ UNARY_OP($$, $2, -); }
403 	| '~' pp_expr			{ UNARY_OP($$, $2, ~); }
404 	| '!' pp_expr			{ $$.type = cv_sint; $$.val.si = !boolean(&$2); }
405 	| '(' pp_expr ')'		{ $$ =  $2; }
406 	| pp_expr '?' pp_expr ':' pp_expr { $$ = boolean(&$1) ? $3 : $5; }
407 	;
408 
409 %%
410 
411 /*
412  **************************************************************************
413  * Support functions
414  **************************************************************************
415  */
416 
417 static void cast_to_sint(cval_t *v)
418 {
419 	switch(v->type)
420 	{
421 	case cv_sint:	break;
422 	case cv_uint:	break;
423 	case cv_slong:	v->val.si = v->val.sl;	break;
424 	case cv_ulong:	v->val.si = v->val.ul;	break;
425 	case cv_sll:	v->val.si = v->val.sll;	break;
426 	case cv_ull:	v->val.si = v->val.ull;	break;
427 	}
428 	v->type = cv_sint;
429 }
430 
431 static void cast_to_uint(cval_t *v)
432 {
433 	switch(v->type)
434 	{
435 	case cv_sint:	break;
436 	case cv_uint:	break;
437 	case cv_slong:	v->val.ui = v->val.sl;	break;
438 	case cv_ulong:	v->val.ui = v->val.ul;	break;
439 	case cv_sll:	v->val.ui = v->val.sll;	break;
440 	case cv_ull:	v->val.ui = v->val.ull;	break;
441 	}
442 	v->type = cv_uint;
443 }
444 
445 static void cast_to_slong(cval_t *v)
446 {
447 	switch(v->type)
448 	{
449 	case cv_sint:	v->val.sl = v->val.si;	break;
450 	case cv_uint:	v->val.sl = v->val.ui;	break;
451 	case cv_slong:	break;
452 	case cv_ulong:	break;
453 	case cv_sll:	v->val.sl = v->val.sll;	break;
454 	case cv_ull:	v->val.sl = v->val.ull;	break;
455 	}
456 	v->type = cv_slong;
457 }
458 
459 static void cast_to_ulong(cval_t *v)
460 {
461 	switch(v->type)
462 	{
463 	case cv_sint:	v->val.ul = v->val.si;	break;
464 	case cv_uint:	v->val.ul = v->val.ui;	break;
465 	case cv_slong:	break;
466 	case cv_ulong:	break;
467 	case cv_sll:	v->val.ul = v->val.sll;	break;
468 	case cv_ull:	v->val.ul = v->val.ull;	break;
469 	}
470 	v->type = cv_ulong;
471 }
472 
473 static void cast_to_sll(cval_t *v)
474 {
475 	switch(v->type)
476 	{
477 	case cv_sint:	v->val.sll = v->val.si;	break;
478 	case cv_uint:	v->val.sll = v->val.ui;	break;
479 	case cv_slong:	v->val.sll = v->val.sl;	break;
480 	case cv_ulong:	v->val.sll = v->val.ul;	break;
481 	case cv_sll:	break;
482 	case cv_ull:	break;
483 	}
484 	v->type = cv_sll;
485 }
486 
487 static void cast_to_ull(cval_t *v)
488 {
489 	switch(v->type)
490 	{
491 	case cv_sint:	v->val.ull = v->val.si;	break;
492 	case cv_uint:	v->val.ull = v->val.ui;	break;
493 	case cv_slong:	v->val.ull = v->val.sl;	break;
494 	case cv_ulong:	v->val.ull = v->val.ul;	break;
495 	case cv_sll:	break;
496 	case cv_ull:	break;
497 	}
498 	v->type = cv_ull;
499 }
500 
501 
502 static void promote_equal_size(cval_t *v1, cval_t *v2)
503 {
504 #define cv_sizeof(v)	((int)(v->type & SIZE_MASK))
505 	int s1 = cv_sizeof(v1);
506 	int s2 = cv_sizeof(v2);
507 #undef cv_sizeof
508 
509 	if(s1 == s2)
510 		return;
511 	else if(s1 > s2)
512 	{
513 		switch(v1->type)
514 		{
515 		case cv_sint:	cast_to_sint(v2); break;
516 		case cv_uint:	cast_to_uint(v2); break;
517 		case cv_slong:	cast_to_slong(v2); break;
518 		case cv_ulong:	cast_to_ulong(v2); break;
519 		case cv_sll:	cast_to_sll(v2); break;
520 		case cv_ull:	cast_to_ull(v2); break;
521 		}
522 	}
523 	else
524 	{
525 		switch(v2->type)
526 		{
527 		case cv_sint:	cast_to_sint(v1); break;
528 		case cv_uint:	cast_to_uint(v1); break;
529 		case cv_slong:	cast_to_slong(v1); break;
530 		case cv_ulong:	cast_to_ulong(v1); break;
531 		case cv_sll:	cast_to_sll(v1); break;
532 		case cv_ull:	cast_to_ull(v1); break;
533 		}
534 	}
535 }
536 
537 
538 static int boolean(cval_t *v)
539 {
540 	switch(v->type)
541 	{
542 	case cv_sint:	return v->val.si != (int)0;
543 	case cv_uint:	return v->val.ui != (unsigned int)0;
544 	case cv_slong:	return v->val.sl != (long)0;
545 	case cv_ulong:	return v->val.ul != (unsigned long)0;
546 	case cv_sll:	return v->val.sll != (wrc_sll_t)0;
547 	case cv_ull:	return v->val.ull != (wrc_ull_t)0;
548 	}
549 	return 0;
550 }
551 
552 static marg_t *new_marg(char *str, def_arg_t type)
553 {
554 	marg_t *ma = pp_xmalloc(sizeof(marg_t));
555 	if(!ma)
556 		return NULL;
557 	ma->arg = str;
558 	ma->type = type;
559 	ma->nnl = 0;
560 	return ma;
561 }
562 
563 static marg_t *add_new_marg(char *str, def_arg_t type)
564 {
565 	marg_t **new_macro_args;
566 	marg_t *ma;
567 	if(!str)
568 		return NULL;
569 	new_macro_args = pp_xrealloc(macro_args, (nmacro_args+1) * sizeof(macro_args[0]));
570 	if(!new_macro_args)
571 		return NULL;
572 	macro_args = new_macro_args;
573 	ma = new_marg(str, type);
574 	if(!ma)
575 		return NULL;
576 	macro_args[nmacro_args] = ma;
577 	nmacro_args++;
578 	return ma;
579 }
580 
581 static int marg_index(char *id)
582 {
583 	int t;
584 	if(!id)
585 		return -1;
586 	for(t = 0; t < nmacro_args; t++)
587 	{
588 		if(!strcmp(id, macro_args[t]->arg))
589 			break;
590 	}
591 	return t < nmacro_args ? t : -1;
592 }
593 
594 static mtext_t *new_mtext(char *str, int idx, def_exp_t type)
595 {
596 	mtext_t *mt = pp_xmalloc(sizeof(mtext_t));
597 	if(!mt)
598 		return NULL;
599 	if(str == NULL)
600 		mt->subst.argidx = idx;
601 	else
602 		mt->subst.text = str;
603 	mt->type = type;
604 	mt->next = mt->prev = NULL;
605 	return mt;
606 }
607 
608 static mtext_t *combine_mtext(mtext_t *tail, mtext_t *mtp)
609 {
610 	if(!tail)
611 		return mtp;
612 
613 	if(!mtp)
614 		return tail;
615 
616 	if(tail->type == exp_text && mtp->type == exp_text)
617 	{
618 		char *new_text;
619 		new_text = pp_xrealloc(tail->subst.text, strlen(tail->subst.text)+strlen(mtp->subst.text)+1);
620 		if(!new_text)
621 			return mtp;
622 		tail->subst.text = new_text;
623 		strcat(tail->subst.text, mtp->subst.text);
624 		free(mtp->subst.text);
625 		free(mtp);
626 		return tail;
627 	}
628 
629 	if(tail->type == exp_concat && mtp->type == exp_concat)
630 	{
631 		free(mtp);
632 		return tail;
633 	}
634 
635 	if(tail->type == exp_concat && mtp->type == exp_text)
636 	{
637 		int len = strlen(mtp->subst.text);
638 		while(len)
639 		{
640 /* FIXME: should delete space from head of string */
641 			if(isspace(mtp->subst.text[len-1] & 0xff))
642 				mtp->subst.text[--len] = '\0';
643 			else
644 				break;
645 		}
646 
647 		if(!len)
648 		{
649 			free(mtp->subst.text);
650 			free(mtp);
651 			return tail;
652 		}
653 	}
654 
655 	if(tail->type == exp_text && mtp->type == exp_concat)
656 	{
657 		int len = strlen(tail->subst.text);
658 		while(len)
659 		{
660 			if(isspace(tail->subst.text[len-1] & 0xff))
661 				tail->subst.text[--len] = '\0';
662 			else
663 				break;
664 		}
665 
666 		if(!len)
667 		{
668 			mtp->prev = tail->prev;
669 			mtp->next = tail->next;
670 			if(tail->prev)
671 				tail->prev->next = mtp;
672 			free(tail->subst.text);
673 			free(tail);
674 			return mtp;
675 		}
676 	}
677 
678 	tail->next = mtp;
679 	mtp->prev = tail;
680 
681 	return mtp;
682 }
683 
684 static char *merge_text(char *s1, char *s2)
685 {
686 	int l1;
687 	int l2;
688 	char *snew;
689 	if(!s1)
690 		return s2;
691 	if(!s2)
692 		return s1;
693 	l1 = strlen(s1);
694 	l2 = strlen(s2);
695 	snew = pp_xrealloc(s1, l1+l2+1);
696 	if(!snew)
697 	{
698 		free(s2);
699 		return s1;
700 	}
701 	s1 = snew;
702 	memcpy(s1+l1, s2, l2+1);
703 	free(s2);
704 	return s1;
705 }
706