view lwlib/lw_expr.c @ 334:f2173d18c73f

Checkpoint
author lost
date Thu, 04 Mar 2010 02:24:38 +0000
parents
children 9f58e3bca6e3
line wrap: on
line source

/*
lwexpr.c

Copyright © 2010 William Astle

This file is part of LWTOOLS.

LWTOOLS is free software: you can redistribute it and/or modify it under the
terms of the GNU General Public License as published by the Free Software
Foundation, either version 3 of the License, or (at your option) any later
version.

This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
more details.

You should have received a copy of the GNU General Public License along with
this program. If not, see <http://www.gnu.org/licenses/>.
*/

#include <config.h>

#include <stdarg.h>
#include <stdio.h>
#include <string.h>

#define ___lw_expr_c_seen___
#include "lw_alloc.h"
#include "lw_expr.h"
#include "lw_error.h"
#include "lw_string.h"

lw_expr_t lw_expr_create(void)
{
	lw_expr_t r;
	
	r = lw_alloc(sizeof(struct lw_expr_priv));
	r -> refcount = 1;
	r -> operands = NULL;

	return r;
}

/* useful for constant expression construction */
/* lw_expr_deref(lw_expr_create(...)) */
/* use of this function on an expression that is not already referenced by the caller */
lw_expr_t lw_expr_deref(lw_expr_t r)
{
	r -> refcount--;
	return r;
}

void lw_expr_destroy(lw_expr_t E)
{
	E -> refcount--;
	if (E -> refcount <= 0)
	{
		struct lw_expr_opers *o;
		for (o = E -> operands; o; o = o -> next)
			lw_expr_destroy(o -> p);
		if (E -> type == lw_expr_type_var)
			lw_free(E -> value2);
		lw_free(E);
	}
}

lw_expr_t lw_expr_copy(lw_expr_t E)
{
	E -> refcount++;
	return E;
}

void lw_expr_add_operand(lw_expr_t E, lw_expr_t O)
{
	struct lw_expr_opers *o, *t;
	
	o = lw_alloc(sizeof(struct lw_expr_opers));
	o -> p = lw_expr_copy(O);
	o -> next = NULL;
	for (t = E -> operands; t && t -> next; t = t -> next)
		/* do nothing */ ;
	
	if (t)
		t -> next = o;
	else
		E -> operands = o;
}

/* actually duplicates the entire expression */
lw_expr_t lw_expr_deepcopy(lw_expr_t E)
{
	lw_expr_t r, t;
	struct lw_expr_opers *o;
	
	r = lw_alloc(sizeof(struct lw_expr_priv));
	*r = *E;
	r -> refcount = 1;

	if (E -> type == lw_expr_type_var)
		r -> value2 = lw_strdup(E -> value2);
	
	for (o = r -> operands; o; o = o -> next)
	{
		lw_expr_add_operand(r, lw_expr_deref(lw_expr_deepcopy(o -> p)));
	}
	
	return r;
}

lw_expr_t lw_expr_build(int exprtype, ...)
{
	va_list args;
	lw_expr_t r;
	int t;
	void *p;
	
	lw_expr_t te1, te2;

	r = lw_expr_create();
	va_start(args, exprtype);

	switch (exprtype)
	{
	case lw_expr_type_int:
		t = va_arg(args, int);
		r -> type = lw_expr_type_int;
		r -> value = t;
		break;

	case lw_expr_type_var:
		p = va_arg(args, char *);
		r -> type = lw_expr_type_var;
		r -> value2 = lw_strdup(p);
		break;

	case lw_expr_type_special:
		t = va_arg(args, int);
		p = va_arg(args, char *);
		r -> type = lw_expr_type_special;
		r -> value2 = p;
		break;

	case lw_expr_type_oper:
		t = va_arg(args, int);
		te1 = va_arg(args, lw_expr_t);
		if (t != lw_expr_oper_com && t != lw_expr_oper_neg)
			te2 = va_arg(args, lw_expr_t);
		else
			te2 = NULL;
		
		r -> type = lw_expr_type_oper;
		r -> value = t;
		lw_expr_add_operand(r, te1);
		lw_expr_add_operand(r, te2);
		break;
	
	default:
		lw_error("Invalid expression type specified to lw_expr_build");
	}
	
	va_end(args);
	return r;
}

void lw_expr_print(lw_expr_t E)
{
	struct lw_expr_opers *o;
	
	for (o = E -> operands; o; o = o -> next)
	{
		lw_expr_print(o -> p);
	}
	
	switch (E -> type)
	{
	case lw_expr_type_int:
		printf("%d ", E -> value);
		break;
	case lw_expr_type_oper:
		switch (E -> value)
		{
		case lw_expr_oper_plus:
			printf("+ ");
			break;
			
		case lw_expr_oper_minus:
			printf("- ");
			break;
			
		case lw_expr_oper_times:
			printf("* ");
			break;
			
		case lw_expr_oper_divide:
			printf("/ ");
			break;
			
		case lw_expr_oper_mod:
			printf("%% ");
			break;
			
		case lw_expr_oper_intdiv:
			printf("\\ ");
			break;
			
		case lw_expr_oper_bwand:
			printf("BWAND ");
			break;
			
		case lw_expr_oper_bwor:
			printf("BWOR ");
			break;
			
		case lw_expr_oper_bwxor:
			printf("BWXOR ");
			break;
			
		case lw_expr_oper_and:
			printf("AND ");
			break;
			
		case lw_expr_oper_or:
			printf("OR ");
			break;
			
		case lw_expr_oper_neg:
			printf("NEG ");
			break;
			
		case lw_expr_oper_com:
			printf("COM ");
			break;
			
		default:
			printf("OPER ");
			break;
		}
		break;
	default:
		printf("ERR ");
		break;
	}
}

/*
Return:
nonzero if expressions are the same (identical pointers or matching values)
zero if expressions are not the same

*/
int lw_expr_compare(lw_expr_t E1, lw_expr_t E2)
{
	struct lw_expr_opers *o1, *o2;

	if (E1 == E2)
		return 1;

	if (!(E1 -> type == E2 -> type && E1 -> value == E2 -> value))
		return 0;

	if (E1 -> type == lw_expr_type_var)
	{
		if (!strcmp(E1 -> value2, E2 -> value2))
			return 1;
		else
			return 0;
	}
	
	if (E1 -> type == lw_expr_type_special)
	{
		if (E1 -> value2 == E2 -> value2)
			return 1;
		else
			return 0;
	}
	
	for (o1 = E1 -> operands, o2 = E2 -> operands; o1 && o2; o1 = o1 -> next, o2 = o2 -> next)
		if (lw_expr_compare(o1 -> p, o2 -> p) == 0)
			return 0;
	if (o1 || o2)
		return 0;	

	return 1;
}

/* return true if E is an operator of type oper */
int lw_expr_isoper(lw_expr_t E, int oper)
{
	if (E -> type == lw_expr_type_oper && E -> value == oper)
		return 1;
	return 0;
}