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