1/*
2 * Copyright (c) 2010 Apple Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * 1.  Redistributions of source code must retain the above copyright
11 *     notice, this list of conditions and the following disclaimer.
12 * 2.  Redistributions in binary form must reproduce the above copyright
13 *     notice, this list of conditions and the following disclaimer in the
14 *     documentation and/or other materials provided with the distribution.
15 * 3.  Neither the name of Apple Inc. ("Apple") nor the names of its
16 *     contributors may be used to endorse or promote products derived from
17 *     this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
20 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
23 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
26 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 *
30 * Portions of this software have been released under the following terms:
31 *
32 * (c) Copyright 1989-1993 OPEN SOFTWARE FOUNDATION, INC.
33 * (c) Copyright 1989-1993 HEWLETT-PACKARD COMPANY
34 * (c) Copyright 1989-1993 DIGITAL EQUIPMENT CORPORATION
35 *
36 * To anyone who acknowledges that this file is provided "AS IS"
37 * without any express or implied warranty:
38 * permission to use, copy, modify, and distribute this file for any
39 * purpose is hereby granted without fee, provided that the above
40 * copyright notices and this notice appears in all source code copies,
41 * and that none of the names of Open Software Foundation, Inc., Hewlett-
42 * Packard Company or Digital Equipment Corporation be used
43 * in advertising or publicity pertaining to distribution of the software
44 * without specific, written prior permission.  Neither Open Software
45 * Foundation, Inc., Hewlett-Packard Company nor Digital
46 * Equipment Corporation makes any representations about the suitability
47 * of this software for any purpose.
48 *
49 * Copyright (c) 2007, Novell, Inc. All rights reserved.
50 * Redistribution and use in source and binary forms, with or without
51 * modification, are permitted provided that the following conditions
52 * are met:
53 *
54 * 1.  Redistributions of source code must retain the above copyright
55 *     notice, this list of conditions and the following disclaimer.
56 * 2.  Redistributions in binary form must reproduce the above copyright
57 *     notice, this list of conditions and the following disclaimer in the
58 *     documentation and/or other materials provided with the distribution.
59 * 3.  Neither the name of Novell Inc. nor the names of its contributors
60 *     may be used to endorse or promote products derived from this
61 *     this software without specific prior written permission.
62 *
63 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
64 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
65 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
66 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY
67 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
68 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
69 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
70 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
71 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
72 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
73 *
74 * @APPLE_LICENSE_HEADER_END@
75 */
76
77#include <nidl.h>
78#include <nametbl.h>
79#include <errors.h>
80#include <astp.h>
81#include <nidlmsg.h>
82#include <nidl_y.h>
83
84static void ASTP_free_exp(
85    AST_exp_n_t * exp
86);
87
88AST_exp_n_t * AST_exp_new
89(
90	unsigned long exp_type
91)
92{
93	AST_exp_n_t * exp = NEW(AST_exp_n_t);
94	exp->exp_type = exp_type;
95	return exp;
96}
97
98AST_exp_n_t * AST_exp_integer_constant
99(
100    parser_location_p location ATTRIBUTE_UNUSED,
101    long value,
102    int int_signed
103)
104{
105	AST_exp_n_t * exp = AST_exp_new(AST_EXP_CONSTANT);
106	exp->exp.constant.type = AST_int_const_k;
107	exp->exp.constant.val.integer = value;
108	exp->exp.constant.int_signed = int_signed;
109	return exp;
110}
111
112AST_exp_n_t * AST_exp_char_constant
113(
114    parser_location_p location,
115    char value
116)
117{
118	AST_exp_n_t * exp = AST_exp_new(AST_EXP_CONSTANT);
119	exp->exp.constant.type = AST_nil_const_k;
120	exp->exp.constant.val.other = AST_char_constant(location, value);
121	return exp;
122}
123
124AST_exp_n_t * AST_exp_identifier
125(
126    parser_location_p location ATTRIBUTE_UNUSED,
127    NAMETABLE_id_t name
128)
129{
130	AST_exp_n_t * exp = AST_exp_new(AST_EXP_CONSTANT);
131	exp->exp.constant.type = AST_nil_const_k;
132	exp->exp.constant.val.other = NULL;
133	exp->exp.constant.name = name;
134	return exp;
135}
136
137AST_exp_n_t * AST_exp_string_constant
138(
139	parser_location_p location,
140	STRTAB_str_t string
141)
142{
143	AST_exp_n_t * exp = AST_exp_new(AST_EXP_CONSTANT);
144	exp->exp.constant.type = AST_nil_const_k;
145	exp->exp.constant.val.other = AST_string_constant(location, string);
146	return exp;
147}
148
149AST_exp_n_t * AST_exp_null_constant
150(
151    parser_location_p location
152)
153{
154	AST_exp_n_t * exp = AST_exp_new(AST_EXP_CONSTANT);
155	exp->exp.constant.type = AST_nil_const_k;
156	exp->exp.constant.val.other = AST_null_constant(location);
157	return exp;
158}
159
160AST_exp_n_t * AST_exp_boolean_constant
161(
162    parser_location_p location,
163    boolean value
164)
165{
166	AST_exp_n_t * exp = AST_exp_new(AST_EXP_CONSTANT);
167	exp->exp.constant.type = AST_nil_const_k;
168	exp->exp.constant.val.other = AST_boolean_constant(location, value);
169	return exp;
170}
171
172AST_exp_n_t * AST_expression
173(
174    parser_location_p location ATTRIBUTE_UNUSED,
175    unsigned long exp_type,
176    AST_exp_n_t * oper1,
177    AST_exp_n_t * oper2,
178    AST_exp_n_t * oper3
179)
180{
181	AST_exp_n_t * exp = AST_exp_new(exp_type);
182	exp->exp.expression.oper1 = oper1;
183	exp->exp.expression.oper2 = oper2;
184	exp->exp.expression.oper3 = oper3;
185
186	return exp;
187}
188
189AST_constant_n_t * AST_constant_from_exp
190(
191    parser_location_p location,
192    AST_exp_n_t * exp
193)
194{
195	AST_constant_n_t * const_return;
196	ASTP_evaluate_expr(location, exp, true);
197	if (exp->exp_type == AST_EXP_CONSTANT)	{
198		if (exp->exp.constant.type == AST_int_const_k)	{
199			const_return = AST_integer_constant(location, exp->exp.constant.val.integer);
200			const_return->int_signed = exp->exp.constant.int_signed;
201		}
202		else	{
203			const_return = exp->exp.constant.val.other;
204		}
205	}
206	else
207		const_return = NULL;
208	return const_return;
209}
210
211/* returns true if the expression is regarded as "simple".
212 * Simple expressions match this criteria:
213 * identifier  (parameter, field)
214 * integer constant
215 * <dereference+>identifier
216 * identifier / [248]
217 * identifier * [248]
218 * identifier - 1
219 * identifier + 1
220 *
221 * */
222boolean ASTP_expr_is_simple
223(
224    parser_location_p location,
225    AST_exp_n_t * exp
226)
227{
228	if (ASTP_evaluate_expr(location, exp, true))	{
229		return true;
230	}
231	switch(exp->exp_type)	{
232		case AST_EXP_CONSTANT:
233			return true;
234			break;
235		case AST_EXP_BINARY_SLASH:
236		case AST_EXP_BINARY_STAR:
237			if (exp->exp.expression.oper1->exp_type == AST_EXP_CONSTANT &&
238					((ASTP_expr_integer_value(location, exp->exp.expression.oper2) == 2) ||
239					(ASTP_expr_integer_value(location, exp->exp.expression.oper2) == 4) ||
240					(ASTP_expr_integer_value(location, exp->exp.expression.oper2) == 8)))
241			{
242				return true;
243			}
244			break;
245		case AST_EXP_BINARY_PLUS:
246		case AST_EXP_BINARY_MINUS:
247			if (exp->exp.expression.oper1->exp_type == AST_EXP_CONSTANT &&
248					ASTP_expr_integer_value(location, exp->exp.expression.oper2) == 1)
249			{
250				return true;
251			}
252			break;
253		case AST_EXP_UNARY_STAR:
254			while(exp->exp_type == AST_EXP_UNARY_STAR)
255				exp = exp->exp.expression.oper1;
256			if (exp->exp_type == AST_EXP_CONSTANT)	{
257
258				return true;
259			}
260			break;
261		case AST_EXP_BINARY_AND:
262			/* could be alignment */
263			if (exp->exp.expression.oper1->exp_type == AST_EXP_BINARY_PLUS
264					&&
265				exp->exp.expression.oper2->exp_type == AST_EXP_UNARY_TILDE)
266			{
267				AST_exp_n_t * op1 = exp->exp.expression.oper1;
268				AST_exp_n_t * op2 = exp->exp.expression.oper2;
269				AST_exp_n_t * ident_exp = op1->exp.expression.oper1;
270				long nval = ASTP_expr_integer_value(location, op1->exp.expression.oper2);
271
272				/* allow one level of indirection for the identifier part */
273				if ((ident_exp->exp_type == AST_EXP_CONSTANT || (
274								ident_exp->exp_type == AST_EXP_UNARY_STAR &&
275								ident_exp->exp.expression.oper1->exp_type == AST_EXP_CONSTANT))
276						&& (nval == 1 || nval == 3 || nval == 7) &&
277						ASTP_expr_integer_value(location, op2->exp.expression.oper1)
278							== nval)
279					return true;
280
281			}
282			break;
283	}
284	return false;
285}
286
287long ASTP_expr_integer_value
288(
289    parser_location_p location,
290    AST_exp_n_t * exp
291)
292{
293	long value;
294	ASTP_evaluate_expr(location, exp, true);
295	if (exp->exp.constant.type == AST_int_const_k)
296		value = exp->exp.constant.val.integer;
297	else	{
298		switch(exp->exp.constant.val.other->kind)	{
299			case AST_int_const_k:
300				value = exp->exp.constant.val.other->value.int_val;
301				break;
302			case AST_char_const_k:
303				value = exp->exp.constant.val.other->value.char_val;
304				break;
305			case AST_boolean_const_k:
306				value = exp->exp.constant.val.other->value.boolean_val;
307				break;
308			default:
309				value = 0;
310		}
311	}
312	return value;
313}
314
315/* Free an expression node and any child operands */
316void ASTP_free_exp(AST_exp_n_t * exp)	{
317	if (exp == NULL)
318		return;
319	if (exp->exp_type != AST_EXP_CONSTANT)	{
320		ASTP_free_exp(exp->exp.expression.oper1);
321		ASTP_free_exp(exp->exp.expression.oper2);
322		ASTP_free_exp(exp->exp.expression.oper3);
323	}
324	FREE(exp);
325}
326
327/* evaluate the expression, reducing it down to a single constant expression
328 * node if possible.
329 * If constant_only is true, this routine will return false when it hits
330 * the name of a parameter to indicate that the expression is not a constant
331 * expression.
332 * */
333boolean ASTP_evaluate_expr
334(
335    parser_location_p location,
336    AST_exp_n_t * exp,
337    boolean constant_only
338)
339{
340	boolean result;
341	long val, val1, val2;
342	AST_exp_n_t * op1=NULL, *op2=NULL, *op3=NULL;
343
344	if (exp == NULL)	{
345		log_warning(location->lineno, NIDL_EXP_IS_NULL, NULL);
346		return true;
347	}
348
349	if (exp->exp_type == AST_EXP_CONSTANT)	{
350		/* resolve binding for identifiers */
351		if (exp->exp.constant.type == AST_nil_const_k &&
352				exp->exp.constant.val.other == NULL)	{
353
354			exp->exp.constant.val.other =
355			    (AST_constant_n_t*)ASTP_lookup_binding(
356				    location,
357				    exp->exp.constant.name,
358				    fe_constant_n_k, FALSE);
359
360			if (exp->exp.constant.val.other == NULL)
361				return false;
362
363		}
364		/* already reduced to the simplest form */
365		return true;
366	} else if (exp->exp_type == AST_EXP_TUPLE) {
367		op1 = exp->exp.expression.oper1;
368
369		if (op1->exp.constant.type == AST_nil_const_k &&
370		    op1->exp.constant.val.other == NULL) {
371		    op1->exp.constant.val.other =
372			(AST_constant_n_t *)ASTP_lookup_binding(
373				location,
374				op1->exp.constant.name,
375				fe_constant_n_k, FALSE);
376		    if (op1->exp.constant.val.other == NULL)
377			return false;
378		}
379
380		op2 = exp->exp.expression.oper2;
381
382		if (op2->exp.constant.type == AST_nil_const_k &&
383		    op2->exp.constant.val.other == NULL) {
384		    op2->exp.constant.val.other =
385			(AST_constant_n_t *)ASTP_lookup_binding(
386				location,
387				op2->exp.constant.name,
388				fe_constant_n_k, FALSE);
389		    if (op2->exp.constant.val.other == NULL)
390			return false;
391		}
392		return true;
393        }
394
395	/* time to evaluate some expressions.
396	 * First, reduce the operands to their simplest forms too */
397
398	result = ASTP_evaluate_expr(location, exp->exp.expression.oper1, constant_only);
399	if (result == false)
400		return false;
401	op1 = exp->exp.expression.oper1;
402
403	if ((exp->exp_type & AST_EXP_2_OP_MASK) != 0)	{
404		result = ASTP_evaluate_expr(location, exp->exp.expression.oper2, constant_only);
405		if (result == false)
406			return false;
407		op2 = exp->exp.expression.oper2;
408	}
409	if ((exp->exp_type & AST_EXP_3_OP_MASK) != 0)	{
410		result = ASTP_evaluate_expr(location, exp->exp.expression.oper3, constant_only);
411		if (result == false)
412			return false;
413		op3 = exp->exp.expression.oper3;
414	}
415	/* only reached if we are dealing with a constant expression,
416	 * and that means that we can play around with the operands */
417	switch(exp->exp_type)	{
418		case AST_EXP_UNARY_NOT:
419			exp->exp.constant.val.integer =
420			    !ASTP_expr_integer_value(location, op1);
421			break;
422		case AST_EXP_UNARY_TILDE:
423			exp->exp.constant.val.integer =
424			    ~ASTP_expr_integer_value(location, op1);
425			break;
426		case AST_EXP_UNARY_PLUS: /* why this? I can't remember what I was thinking */
427			exp->exp.constant.val.integer =
428			    +ASTP_expr_integer_value(location, op1);
429			break;
430		case AST_EXP_UNARY_MINUS:
431			exp->exp.constant.val.integer =
432			    -ASTP_expr_integer_value(location, op1);
433			break;
434		case AST_EXP_UNARY_STAR:
435			return false;
436		case AST_EXP_BINARY_PERCENT:
437			val = ASTP_expr_integer_value(location, op2);
438			if (val == 0)
439				log_error(location->lineno, NIDL_INTDIVBY0, NULL);
440			else
441				val = ASTP_expr_integer_value(location, op1) % val;
442			exp->exp.constant.val.integer = val;
443			break;
444		case AST_EXP_BINARY_SLASH:
445			val = ASTP_expr_integer_value(location, op2);
446			if (val == 0)
447				log_error(location->lineno, NIDL_INTDIVBY0, NULL);
448			else
449				val = ASTP_expr_integer_value(location, op1) / val;
450			exp->exp.constant.val.integer = val;
451			break;
452		case AST_EXP_BINARY_STAR:
453			val1 = ASTP_expr_integer_value(location, op1);
454			val2 = ASTP_expr_integer_value(location, op2);
455			val = val1 * val2;
456			if (val < val1 && val > val2)
457				log_error(location->lineno, NIDL_INTOVERFLOW, KEYWORDS_lookup_text(LONG_KW), NULL);
458			exp->exp.constant.val.integer = val;
459			break;
460		case AST_EXP_BINARY_MINUS:
461			exp->exp.constant.val.integer =
462			    ASTP_expr_integer_value(location, op1) -
463			    ASTP_expr_integer_value(location, op2);
464			break;
465		case AST_EXP_BINARY_PLUS:
466			exp->exp.constant.val.integer =
467			    ASTP_expr_integer_value(location, op1) +
468			    ASTP_expr_integer_value(location, op2);
469			break;
470		case AST_EXP_BINARY_RSHIFT:
471			exp->exp.constant.val.integer =
472			    ASTP_expr_integer_value(location, op1) >>
473			    ASTP_expr_integer_value(location, op2);
474			break;
475		case AST_EXP_BINARY_LSHIFT:
476			exp->exp.constant.val.integer =
477			    ASTP_expr_integer_value(location, op1) <<
478			    ASTP_expr_integer_value(location, op2);
479			break;
480		case AST_EXP_BINARY_GE:
481			exp->exp.constant.val.integer =
482			    ASTP_expr_integer_value(location, op1) >=
483			    ASTP_expr_integer_value(location, op2);
484			break;
485		case AST_EXP_BINARY_LE:
486			exp->exp.constant.val.integer =
487			    ASTP_expr_integer_value(location, op1) <=
488			    ASTP_expr_integer_value(location, op2);
489			break;
490		case AST_EXP_BINARY_GT:
491			exp->exp.constant.val.integer =
492			    ASTP_expr_integer_value(location, op1) >
493			    ASTP_expr_integer_value(location, op2);
494			break;
495		case AST_EXP_BINARY_LT:
496			exp->exp.constant.val.integer =
497			    ASTP_expr_integer_value(location, op1) <
498			    ASTP_expr_integer_value(location, op2);
499			break;
500		case AST_EXP_BINARY_NE:
501			exp->exp.constant.val.integer =
502			    ASTP_expr_integer_value(location, op1) !=
503			    ASTP_expr_integer_value(location, op2);
504			break;
505		case AST_EXP_BINARY_EQUAL:
506			exp->exp.constant.val.integer =
507			    ASTP_expr_integer_value(location, op1) ==
508			    ASTP_expr_integer_value(location, op2);
509			break;
510		case AST_EXP_BINARY_AND:
511			exp->exp.constant.val.integer =
512			    ASTP_expr_integer_value(location, op1) &
513			    ASTP_expr_integer_value(location, op2);
514			break;
515		case AST_EXP_BINARY_OR:
516			exp->exp.constant.val.integer =
517			    ASTP_expr_integer_value(location, op1) |
518			    ASTP_expr_integer_value(location, op2);
519			break;
520		case AST_EXP_BINARY_XOR:
521			exp->exp.constant.val.integer =
522			    ASTP_expr_integer_value(location, op1) ^
523			    ASTP_expr_integer_value(location, op2);
524			break;
525		case AST_EXP_BINARY_LOG_AND:
526			exp->exp.constant.val.integer =
527			    ASTP_expr_integer_value(location, op1) &&
528			    ASTP_expr_integer_value(location, op2);
529			break;
530		case AST_EXP_BINARY_LOG_OR:
531			exp->exp.constant.val.integer =
532			    ASTP_expr_integer_value(location, op1) ||
533			    ASTP_expr_integer_value(location, op2);
534			break;
535		case AST_EXP_TERNARY_OP:
536			/* we want to preserve the type for this, so we short-circuit the return */
537            if (ASTP_expr_integer_value(location, op1)) {
538                assert(op2 != NULL);
539                *exp = *op2;
540            }
541            else {
542                assert(op3 != NULL);
543                *exp = *op3;
544            }
545            return true;
546		default:
547			/* NOTREACHED (hopefully!) */
548			break;
549	}
550	ASTP_free_exp(op1);
551	ASTP_free_exp(op2);
552	ASTP_free_exp(op3);
553	exp->exp_type = AST_EXP_CONSTANT;
554	exp->exp.constant.type = AST_int_const_k;
555	return true;
556}
557