Пример #1
0
int bool_expr(bool op,oprtype *addr)
{
	oprtype x;
	DCL_THREADGBL_ACCESS;

	SETUP_THREADGBL_ACCESS;
	if (!(TREF(expr_depth))++)
		TREF(expr_start) = TREF(expr_start_orig) = NULL;
	if (!eval_expr(&x))
	{
		TREF(expr_depth) = 0;
		return FALSE;
	}
	coerce(&x, OCT_BOOL);
	if (!(--(TREF(expr_depth))))
		TREF(shift_side_effects) = FALSE;
	assert(x.oprclass == TRIP_REF);
	bx_tail(x.oprval.tref, op, addr);
	return TRUE;
}
Пример #2
0
/// Evaluates the expression str using the vim internal expression
/// evaluator (see |expression|).
/// Dictionaries and lists are recursively expanded.
///
/// @param str The expression str
/// @param[out] err Details of an error that may have occurred
/// @return The expanded object
Object vim_eval(String str, Error *err)
{
  Object rv;
  // Evaluate the expression
  try_start();
  typval_T *expr_result = eval_expr((char_u *) str.data, NULL);

  if (!expr_result) {
    set_api_error("Failed to eval expression", err);
  }

  if (!try_end(err)) {
    // No errors, convert the result
    rv = vim_to_object(expr_result);
  }

  // Free the vim object
  free_tv(expr_result);
  return rv;
}
Пример #3
0
void
main(void)
{
  struct eval_state_t *es;

  /* set up test variables */
  an_int.type = et_int; an_int.value.as_int = 1;
  a_uint.type = et_uint; a_uint.value.as_uint = 2;
  a_float.type = et_float; a_float.value.as_float = 3.0f;
  a_double.type = et_double; a_double.value.as_double = 4.0;
  a_symbol.type = et_symbol; a_symbol.value.as_symbol = "testing 1 2 3...";

  /* instantiate an evaluator */
  es = eval_new(my_eval_ident, NULL);

  while (1)
    {
      struct eval_value_t val;
      char expr_buf[1024];

      fgets(expr_buf, 1024, stdin);

      /* chop */
      if (expr_buf[strlen(expr_buf)-1] == '\n')
	expr_buf[strlen(expr_buf)-1] = '\0';

      if (expr_buf[0] == '\0')
	exit(0);

      val = eval_expr(es, expr_buf, NULL);
      if (eval_error)
	fprintf(stdout, "eval error: %s\n", eval_err_str[eval_error]);
      else
	{
	  fprintf(stdout, "%s == ", expr_buf);
	  eval_print(stdout, val);
	  fprintf(stdout, "\n");
	}
    }
}
Пример #4
0
Файл: ddl.c Проект: mpw/p2
void
print_expr (LISTNODE *p)
{
#if 0

  LISTNODE *q = p;
  size_t len = 0;
  char *s;
  long e;

  /* Calculate the length of the expr. */
  for (q = p; q != NULL_LIST; q = q->next)
    len = len + strlen(q->text);
  /* Allocate a string buffer. */
  s = (char *) xmalloc(len+1);
  /* Print the expr in the string buffer. */
  *s = '\0';
  for (q = p; q != NULL_LIST; q = q->next) {
    strcat(s, q->text);
    strcat(s, " ");
  }
  printf("\"");
  /* If possible, simplify the expression. */
  if (eval_expr(s, &e))
    printf("%ld", e);
  else
    printf("%s", s);
  printf("\"");

#else

  printf("\"");
  do {   
    printf("%s ", p->text);
    p = p->next;
  } while (p != NULL_LIST);
  printf("\"");

#endif
}
Пример #5
0
bool
eval_qual_set(int nquals, ExprState **qual_ary)
{
    int i;

    for (i = 0; i < nquals; i++)
    {
        ExprState *qual_state = qual_ary[i];
        Datum result;

        /*
         * Sanity check: we already require the return type of qual
         * expressions to be boolean in the analysis phase
         */
        ASSERT(qual_state->expr->type == TYPE_BOOL);

        result = eval_expr(qual_state);
        if (result.b == false)
            return false;
    }

    return true;
}
Пример #6
0
int	main(int ac, char **av)
{
  char *buff;
  t_nbr	res;

  if (ac != 4)
    {
      my_putstr("usage : ");
      my_putstr(av[0]);
      my_putstr("base ops\"()+-*/%\" exp_len\n");
      return (1);
    }
  check_size(av);
  buff = buffer(av[3]);
  global_error(av, buff);
  trad_base_to_ascii(av, buff);
  my_init_zero(&res);
  eval_expr(buff, &res, my_strlen(av[1]));
  trad_ascii_to_base(av, &res);
  free(res.str);
  free(buff);
  return (0);
}
Пример #7
0
/*
** Main function. Given by the subject.
** When you use this program to compute very large numbers, use the -p
** parramater to enable progress bar display.
** Ex : ./calc "01" "()+-x/%" 999999999 -p
*/
int main(int ac, char **av)
{
  unsigned int size;
  char *expr;
  int p;

  p = 0;
  if (ac != 4 && ac != 5)
    {
     my_putstr("Usage : ");
     my_putstr(av[0]);
     my_putstr(" base (\"0123456789\") ops (\"()+-*/%\") exp_len\n");
     exit(1);
   }
  else if (ac == 5 && strcmp(av[4], "-p") == 0)
    p = 1;
  check_base(av[1]);
  check_ops(av[2]);
  size = my_atoi(av[3]);
  expr = get_expr(size);
  eval_expr(av[1], av[2], expr, size, p);
  free(expr);
  exit(0);
}
Пример #8
0
int		main(int ac, char **av)
{
  char		*expr;
  unsigned int	size;

  if (ac != 4)
  {
    my_putstr("Usage : ");
    my_putstr(av[0]);
    my_putstr(" base ops\"()+-*/%\" exp_len\n");
    return (0);
  }
  if (check_base(av[1]) == 1)
    return (0);
  if (check_ops(av[2]) == 1)
    return (0);
  size = my_atoi(av[3]);
  expr = get_expr(size);
  if (expr == NULL)
    return (0);
  my_putstr(eval_expr(av[1], av[2], expr, size));
  my_putstr("\n");
  return (0);
}
Пример #9
0
double eval(FILE* stream, char allowed_nums[4], char* ok)
{
    int i, c;
    double result;
    struct eval_ctx ctx;
    ctx.stream = stream;
    ctx.err = NULL;

    /* we make a copy instead of pointing to the original array so that the can
       remove the numbers when we see them in the expression */
    memcpy(ctx.allowed_nums, allowed_nums, sizeof allowed_nums);

    result = eval_expr(&ctx);

    if((c = getc(stream)) != '\n' && c != EOF)
    {   /* still got characters in the stream */
        if(!ctx.err)
            ctx.err = "Unexpected character";

        consume_line(stream);
    }

    for (i = 0; !ctx.err && i < 4; i++)
        if(ctx.allowed_nums[i] != -1)
            ctx.err = "Not all numbers were used";

    if (ctx.err)
    {
        puts(ctx.err);
        *ok = 0;
        return 0.;
    }

    *ok = 1;
    return result;
}
Пример #10
0
static double eval_value(struct eval_ctx* ctx)
{
    char tok;
    double res;

    if (eval_consume(ctx, "("))
    {   /* got a parenthesis, evaluate its contents and use it as value */
        res = eval_expr(ctx);
        if (!eval_consume(ctx, ")"))
        {
            ctx->err = "Parenthesis not closed";
            return 0.;
        }
        return res;
    }

    if ((tok = eval_consume(ctx, "123456789")))
    {   /* got a number (we only support single-digit numbers) */
        char num = tok - '0';   /* convert from character to number */
        if (mark_number(ctx->allowed_nums, num))
        {
            res = (double) num;
            return res;
        }
        else
        {
            ctx->err = "Number not allowed";
            /*ctx->cur--; /* report error at right spot */
            return 0.;
        }
    }

    /* got something we can't parse as a value */
    ctx->err = "Unexpected character";
    return 0.;
}
Пример #11
0
/* execute assignment operation */
int do_assign(struct sip_msg* msg, struct action* a)
{
	int ret;
	pv_value_t val;
	pv_spec_p dspec;

	ret = -1;
	dspec = (pv_spec_p)a->elem[0].u.data;
	if(!pv_is_w(dspec))
	{
		LM_ERR("read only PV in left expression\n");
		goto error;
	}

	memset(&val, 0, sizeof(pv_value_t));
	if(a->elem[1].type != NULLV_ST)
	{
		ret = eval_expr((struct expr*)a->elem[1].u.data, msg, &val);
		if(!((val.flags&PV_VAL_STR)||(val.flags&PV_VAL_INT))) {
			LM_ERR("no value in right expression\n");
			goto error;
		}
	}

	switch ((unsigned char)a->type){
		case EQ_T:
		case COLONEQ_T:
		case PLUSEQ_T:
		case MINUSEQ_T:
		case DIVEQ_T:
		case MULTEQ_T:
		case MODULOEQ_T:
		case BANDEQ_T:
		case BOREQ_T:
		case BXOREQ_T:
			script_trace("assign",
				(unsigned char)a->type == EQ_T      ? "equal" :
				(unsigned char)a->type == COLONEQ_T ? "colon-eq" :
				(unsigned char)a->type == PLUSEQ_T  ? "plus-eq" :
				(unsigned char)a->type == MINUSEQ_T ? "minus-eq" :
				(unsigned char)a->type == DIVEQ_T   ? "div-eq" :
				(unsigned char)a->type == MULTEQ_T  ? "mult-eq" :
				(unsigned char)a->type == MODULOEQ_T? "modulo-eq" :
				(unsigned char)a->type == BANDEQ_T  ? "b-and-eq" :
				(unsigned char)a->type == BOREQ_T   ? "b-or-eq":"b-xor-eq",
				msg, a->line);

			if(a->elem[1].type == NULLV_ST)
			{
				if(pv_set_value(msg, dspec, (int)a->type, 0)<0)
				{
					LM_ERR("setting PV failed\n");
					goto error;
				}
			} else {
				if(pv_set_value(msg, dspec, (int)a->type, &val)<0)
				{
					LM_ERR("setting PV failed\n");
					goto error;
				}
			}
			ret = 1;
		break;
		default:
			LM_ALERT("BUG -> unknown op type %d\n", a->type);
			goto error;
	}

	pv_value_destroy(&val);
	return ret;

error:
	LM_ERR("error at line: %d\n", a->line);
	pv_value_destroy(&val);
	return -1;
}
Пример #12
0
LONG_DOUBLE eval_expr_func(eval_context *ctx, ast_node *tree) {
    expr_func_data *func_data = (expr_func_data*)tree->data;
    if (strcmp(func_data->name, "sin") == 0) return sinl(eval_expr(ctx, func_data->rhs));
    else if (strcmp(func_data->name, "cos") == 0) return cosl(eval_expr(ctx, func_data->rhs));
    else if (strcmp(func_data->name, "tan") == 0) return tanl(eval_expr(ctx, func_data->rhs));
    else if (strcmp(func_data->name, "acos") == 0) return acosl(eval_expr(ctx, func_data->rhs));
    else if (strcmp(func_data->name, "asin") == 0) return asinl(eval_expr(ctx, func_data->rhs));
    else if (strcmp(func_data->name, "atan") == 0) return atanl(eval_expr(ctx, func_data->rhs));
    else if (strcmp(func_data->name, "cosh") == 0) return coshl(eval_expr(ctx, func_data->rhs));
    else if (strcmp(func_data->name, "sinh") == 0) return sinhl(eval_expr(ctx, func_data->rhs));
    else if (strcmp(func_data->name, "tanh") == 0) return tanhl(eval_expr(ctx, func_data->rhs));
    else if (strcmp(func_data->name, "log") == 0) return logl(eval_expr(ctx, func_data->rhs));
    else if (strcmp(func_data->name, "log10") == 0) return log10l(eval_expr(ctx, func_data->rhs));
    else if (strcmp(func_data->name, "ceil") == 0) return ceill(eval_expr(ctx, func_data->rhs));
    else if (strcmp(func_data->name, "fabs") == 0) return fabsl(eval_expr(ctx, func_data->rhs));
    else if (strcmp(func_data->name, "floor") == 0) return floorl(eval_expr(ctx, func_data->rhs));
    else if (strcmp(func_data->name, "sqrt") == 0) return sqrtl(eval_expr(ctx, func_data->rhs));
    else return eval_emit_error(ctx, "Unknown function %s.", func_data->name);
}
Пример #13
0
LONG_DOUBLE eval_expr_binop(eval_context *ctx, ast_node *tree) {
    expr_binop_data *binop_data = (expr_binop_data*)tree->data;
    switch (binop_data->op) {
    case OP_ADD:
        return eval_expr(ctx, binop_data->lhs) + eval_expr(ctx, binop_data->rhs);
    case OP_SUB:
        return eval_expr(ctx, binop_data->lhs) - eval_expr(ctx, binop_data->rhs);
    case OP_MUL:
        return eval_expr(ctx, binop_data->lhs) * eval_expr(ctx, binop_data->rhs);
    case OP_DIV:
        return eval_expr(ctx, binop_data->lhs) / eval_expr(ctx, binop_data->rhs);
    case OP_MOD: {
        // Knuthsche "floored division"
        LONG_DOUBLE a = eval_expr(ctx, binop_data->lhs);
        LONG_DOUBLE n = eval_expr(ctx, binop_data->rhs);
        return a-n*floor(a/n);
    }
    case OP_EXP:
        return pow(eval_expr(ctx, binop_data->lhs), eval_expr(ctx, binop_data->rhs));
    case OP_ASS: {
        if (binop_data->lhs->type != EXPR_VAR) return eval_emit_error(ctx, "Cannot assign to a non-variable.");
        else {
            expr_var_data *var_data = (expr_var_data*)binop_data->lhs->data;
            LONG_DOUBLE rhs_res = eval_expr(ctx, binop_data->rhs);
            store_var(store_get(), var_data->name, rhs_res);
            return rhs_res;
        }
    }
    default: return eval_emit_error(ctx, "Operator not implemented.");
    }
}
Пример #14
0
// Starts the algorithm with the required parameters
void startGenerations(int targetNumber, uint maxGenerations, uint geneCountMin, uint geneCountMax, uint logThreshold)
{
	bool solutionFound = false;
	int generation = 0;
	Chromosome *fittestChromosome = NULL;
	float bestFitness = 0;
	
	// Run the simulation until a solution has been found or the maximum number of generations has been reached
	for (unsigned int i = 0; !solutionFound && (maxGenerations == 0 || i < maxGenerations); ++i)
	{
		bool writeLog = logThreshold && (generation % logThreshold == 0);
		
		if (writeLog)
			std::cout << "Generation " << generation << '\n'; 
		
		Chromosome *newChromosome = NULL;
		
		if (fittestChromosome)
			newChromosome = new Chromosome(*fittestChromosome);
		else
			newChromosome = new Chromosome(geneCountMin, geneCountMax);
		
		int result = 0;
		eval_expr(newChromosome->getSanitized(), result);
		if (writeLog)
			std::cout << "Chromosome result: " << result << '\n';
		
		if (result != targetNumber) // Solution not yet found
		{
			float fitness = getFitness(result, targetNumber);
			
			if (writeLog)
				std::cout << "Chromosome fitness: " << fitness;
			
			if (fitness > bestFitness)
			{
				if (writeLog)
					std::cout << " -> selected\n";
				
				if (fittestChromosome)
					delete fittestChromosome;
				fittestChromosome = newChromosome;
				bestFitness = fitness;
			}
			else
			{
				if (writeLog)
					std::cout << " -> rejected\n";
				delete newChromosome;
			}
		}
		else // Solution found
		{
			if (fittestChromosome)
				delete fittestChromosome;
			fittestChromosome = newChromosome;
			
			solutionFound = true;
		}
		
		if (writeLog)
			std::cout << std::endl;
		
		++generation;
	}
	
	std::cout << "Target number: " << targetNumber << '\n'
		<< "Solution " << (solutionFound ? "" : "not ") << "found after " << generation << " generations" << std::endl;
	
	if (fittestChromosome)
	{
		if (solutionFound)
			fittestChromosome->displayInfo();
		
		delete fittestChromosome;
	}
}
Пример #15
0
LONG_DOUBLE eval_expr_nop(eval_context *ctx, ast_node *tree) {
    expr_nop_data *nop_data = (expr_nop_data*)tree->data;
    return eval_expr(ctx, nop_data->next);
}
Пример #16
0
Файл: vasm.c Проект: ezrec/vasm
static void assemble(void)
{
    section *sec;
    atom *p;
    char *attr;
    int bss;

    final_pass=1;
    for(sec=first_section; sec; sec=sec->next) {
        source *lasterrsrc=NULL;
        int lasterrline=0;
        sec->pc=sec->org;
        attr=sec->attr;
        bss=0;
        while(*attr) {
            if(*attr++=='u') {
                bss=1;
                break;
            }
        }
        for(p=sec->first; p; p=p->next) {
            sec->pc=(sec->pc+p->align-1)/p->align*p->align;
            cur_src=p->src;
            cur_src->line=p->line;
            if(p->list&&p->list->atom==p) {
                p->list->sec=sec;
                p->list->pc=sec->pc;
            }
            if(p->type==INSTRUCTION) {
                dblock *db;
                cur_listing=p->list;
                db=eval_instruction(p->content.inst,sec,sec->pc);
                if(pic_check)
                    do_pic_check(db->relocs);
                cur_listing=0;
                if(DEBUG) {
                    if(db->size!=instruction_size(p->content.inst,sec,sec->pc))
                        ierror(0);
                }
                /*FIXME: sauber freigeben */
                myfree(p->content.inst);
                p->content.db=db;
                p->type=DATA;
            }
            else if(p->type==DATADEF) {
                dblock *db;
                cur_listing=p->list;
                db=eval_data(p->content.defb->op,p->content.defb->bitsize,sec,sec->pc);
                if(pic_check)
                    do_pic_check(db->relocs);
                cur_listing=0;
                /*FIXME: sauber freigeben */
                myfree(p->content.defb);
                p->content.db=db;
                p->type=DATA;
            }
            else if(p->type==RORG) {
                sblock *sb;
                taddr space;
                if(eval_expr(p->content.roffs,&space,sec,sec->pc)) {
                    space=sec->org+space-sec->pc;
                    if (space>=0) {
                        sb=new_sblock(number_expr(space),1,0);
                        p->content.sb=sb;
                        p->type=SPACE;
                    }
                    else
                        general_error(20);  /* rorg is lower than current pc */
                }
                else
                    general_error(30);  /* expression must be constant */
            }
            else if(p->type==DATA&&bss) {
                if(lasterrsrc!=p->src||lasterrline!=p->line) {
                    general_error(31);  /* initialized data in bss */
                    lasterrsrc=p->src;
                    lasterrline=p->line;
                }
            }
#ifdef HAVE_CPU_OPTS
            else if(p->type==OPTS)
                cpu_opts(p->content.opts);
#endif
            else if(p->type==PRINTTEXT)
                printf("%s\n",p->content.ptext);
            else if (p->type==PRINTEXPR) {
                taddr val;
                eval_expr(p->content.pexpr,&val,sec,sec->pc);
                printf("%ld (0x%lx)\n",(long)val,(unsigned long)val);
            }
            sec->pc+=atom_size(p,sec,sec->pc);
        }
    }
}
Пример #17
0
static int
parse_arith(char **word, size_t * word_length, size_t * max_length,
			const char *words, size_t * offset, int flags, int bracket)
{
	/* We are poised just after "$((" or "$[" */
	int error;
	int paren_depth = 1;
	size_t expr_length;
	size_t expr_maxlen;
	char *expr;

	expr = w_newword(&expr_length, &expr_maxlen);
	for (; words[*offset]; ++(*offset)) {
		switch (words[*offset]) {
		case '$':
			error = parse_dollars(&expr, &expr_length, &expr_maxlen,
								  words, offset, flags, NULL, NULL, NULL,
								  1);
			/* The ``1'' here is to tell parse_dollars not to
			 * split the fields.
			 */
			if (error) {
				free(expr);
				return error;
			}
			break;

		case '`':
			(*offset)++;
			error = parse_backtick(&expr, &expr_length, &expr_maxlen,
								   words, offset, flags, NULL, NULL, NULL);
			/* The first NULL here is to tell parse_backtick not to
			 * split the fields.
			 */
			if (error) {
				free(expr);
				return error;
			}
			break;

		case '\\':
			error = parse_qtd_backslash(&expr, &expr_length, &expr_maxlen,
										words, offset);
			if (error) {
				free(expr);
				return error;
			}
			/* I think that a backslash within an
			 * arithmetic expansion is bound to
			 * cause an error sooner or later anyway though.
			 */
			break;

		case ')':
			if (--paren_depth == 0) {
				char result[21];	/* 21 = ceil(log10(2^64)) + 1 */
				long int numresult = 0;
				long long int convertme;

				if (bracket || words[1 + *offset] != ')') {
					free(expr);
					return WRDE_SYNTAX;
				}

				++(*offset);

				/* Go - evaluate. */
				if (*expr && eval_expr(expr, &numresult) != 0) {
					free(expr);
					return WRDE_SYNTAX;
				}

				if (numresult < 0) {
					convertme = -numresult;
					*word = w_addchar(*word, word_length, max_length, '-');
					if (!*word) {
						free(expr);
						return WRDE_NOSPACE;
					}
				} else
					convertme = numresult;

				result[20] = '\0';
				*word = w_addstr(*word, word_length, max_length,
								 _itoa(convertme, &result[20]));
				free(expr);
				return *word ? 0 : WRDE_NOSPACE;
			}
			expr =
				w_addchar(expr, &expr_length, &expr_maxlen,
						  words[*offset]);
			if (expr == NULL)
				return WRDE_NOSPACE;

			break;

		case ']':
			if (bracket && paren_depth == 1) {
				char result[21];	/* 21 = ceil(log10(2^64)) + 1 */
				long int numresult = 0;

				/* Go - evaluate. */
				if (*expr && eval_expr(expr, &numresult) != 0) {
					free(expr);
					return WRDE_SYNTAX;
				}

				result[20] = '\0';
				*word = w_addstr(*word, word_length, max_length,
								 _itoa(numresult, &result[20]));
				free(expr);
				return *word ? 0 : WRDE_NOSPACE;
			}

			free(expr);
			return WRDE_SYNTAX;

		case '\n':
		case ';':
		case '{':
		case '}':
			free(expr);
			return WRDE_BADCHAR;

		case '(':
			++paren_depth;
		default:
			expr =
				w_addchar(expr, &expr_length, &expr_maxlen,
						  words[*offset]);
			if (expr == NULL)
				return WRDE_NOSPACE;
		}
	}

	/* Premature end */
	free(expr);
	return WRDE_SYNTAX;
}
Пример #18
0
int main(int argc, char **argv)
{
	Atom expr;
	Atom result;
	Atom env;

	Error err;
	char input[MAXLINE];
	char *end = input;

	env_init(&env);	
	//print_expr(env);

	FILE *fp = NULL;
	/* no arguments were passed */
	if(argc < 2)
		fp = stdin;
	else {
		fp = fopen(argv[1], "r");
		if(fp == NULL)
		{
		      fprintf(stderr, "Cannot open file %s\n", argv[1]);
		      return -1;
	   	}
		const char * file_extension = get_filename_extension(argv[1]);
		if(strcmp(file_extension, "liuyong") != 0)
		{
		      fprintf(stderr, "file extension must be .liuyong\n");
		      return -1;
	   	}
	}
	
	
	printf("> ");
	while(fgets(input, MAXLINE, fp) != NULL)
	{
		err = read_expr(input, &end, &expr);
		//print_expr(expr);
		if(!err)
			err = eval_expr(expr, env, &result);
		switch(err)
		{
			case ERROR_OK:
				print_expr(result);
				printf("\n");
				break;
			case ERROR_SYNTAX:
				printf("Syntax Error\n");
				break;
			case ERROR_UNBOUND:
				printf("Symbol Not Bound\n");
				break;
			case ERROR_TYPE:
				printf("Wrong Type\n");
				break;
			case ERROR_ARGS:
				printf("Wrong Nomber Of Arguments\n");
				break;
		}
		printf("> ");
	}
}
Пример #19
0
/* evaluate a stat as an expression */
struct eval_value_t
stat_eval_ident(struct eval_state_t *es)/* an expression evaluator */
{
  struct stat_sdb_t *sdb = es->user_ptr;
  struct stat_stat_t *stat;
  static struct eval_value_t err_value = { et_int, { 0 } };
  struct eval_value_t val;

  /* locate the stat variable */
  for (stat = sdb->stats; stat != NULL; stat = stat->next)
    {
      if (!strcmp(stat->name, es->tok_buf))
	{
	  /* found it! */
	  break;
	}
    }
  if (!stat)
    {
      /* could not find stat variable */
      eval_error = ERR_UNDEFVAR;
      return err_value;
    }
  /* else, return the value of stat */

  /* convert the stat variable value to a typed expression value */
  switch (stat->sc)
    {
    case sc_int:
      val.type = et_int;
      val.value.as_int = *stat->variant.for_int.var;
      break;
    case sc_uint:
      val.type = et_uint;
      val.value.as_uint = *stat->variant.for_uint.var;
      break;
#ifdef HOST_HAS_QWORD
    case sc_qword:
      /* FIXME: cast to double, eval package doesn't support long long's */
      val.type = et_double;
#ifdef _MSC_VER /* FIXME: MSC does not implement qword_t to dbl conversion */
      val.value.as_double = (double)(sqword_t)*stat->variant.for_qword.var;
#else /* !_MSC_VER */
      val.value.as_double = (double)*stat->variant.for_qword.var;
#endif /* _MSC_VER */
      break;
    case sc_sqword:
      /* FIXME: cast to double, eval package doesn't support long long's */
      val.type = et_double;
      val.value.as_double = (double)*stat->variant.for_sqword.var;
      break;
#endif /* HOST_HAS_QWORD */
    case sc_float:
      val.type = et_float;
      val.value.as_float = *stat->variant.for_float.var;
      break;
    case sc_double:
      val.type = et_double;
      val.value.as_double = *stat->variant.for_double.var;
      break;
    case sc_dist:
    case sc_sdist:
      fatal("stat distributions not allowed in formula expressions");
      break;
    case sc_formula:
      {
	/* instantiate a new evaluator to avoid recursion problems */
	struct eval_state_t *es = eval_new(stat_eval_ident, sdb);
	char *endp;

	val = eval_expr(es, stat->variant.for_formula.formula, &endp);
	if (eval_error != ERR_NOERR || *endp != '\0')
	  {
	    /* pass through eval_error */
	    val = err_value;
	  }
	/* else, use value returned */
	eval_delete(es);
      }
      break;
    default:
      panic("bogus stat class");
    }

  return val;
}
Пример #20
0
static double eval_item(const char *buf, int *pos) /* item = -item | +item | int | var | (expr) */
{
	double rv = 0.0;
	void *data;
	int tlen, nargs, xargs;
	DB(int i);
	FunctionPtr fn;
	DB(char *fname);
	Token tok;
	
	DB(printf("-- eval_item(\"%s\", &pos=%p pos=%d)\n", buf+*pos, pos, *pos));
	tok = pull_token(buf, pos);
	if(G_eval_error)
		return rv;
	DB(printf("-- item token type '%c' = ", tok.type));
	switch(tok.type)
	{
	case '+': /* positive */
		DB(printf("positive\n"));
		rv = eval_fact(buf, pos);
		break;
	case '-': /* negative */
		DB(printf("negative\n"));
		rv = -eval_fact(buf, pos);
		break;
	case 'v': /* variable */
		DB(printf("variable name '%s'=%f\n", tok.str, tok.value));
		rv = tok.value;
		break;
	case 'f': /* function */
		DB(printf("function name '%s'=%p(%d)\n", tok.str, tok.fn, tok.args));
		tlen = tok.args;
		nargs = tok.args;
		xargs = nargs;
		data = tok.data;
		fn = tok.fn;
		DB(fname = tok.str);
		tok = pull_token(buf, pos);
		if(G_eval_error == 0)
		{
			if(tok.type != '(')
				G_eval_error = EVAL_SYNTAX_ERROR;
			else
			{
				double *targ = NULL;
				
				if(tlen > 0)
				{
					targ = (double*)lalloc(sizeof(double)*tlen);
					if(targ == NULL)
					{
						G_eval_error = EVAL_MEM_ERROR;
						break;
					}
				}else
					tlen = 0;
				if(eval_args(buf, pos, &nargs, &targ, &tlen, 0))
					break;
				DB(printf("-- item %d arguments\n", nargs));
				if(xargs < 0)
				{
					if(nargs < 1)
					{
						DB(printf("-- item too few arguments\n"));
						G_eval_error = EVAL_ARGS_ERROR;
						break;
					}
				}else if(nargs != xargs)
				{
					DB(printf("-- item bad argument count (%d) need %d\n",
						nargs, xargs));
					G_eval_error = EVAL_ARGS_ERROR;
					break;
				}
				tok = pull_token(buf, pos);
				if(tok.type != ')')
					G_eval_error = EVAL_SYNTAX_ERROR;
				else if(G_eval_error == 0)
				{
					DB(printf("-- call function [%p] with %d args [%p]\n",
						fn, nargs, targ));
					DB(printf("-- %s(%f", fname, targ[0]));
					DB(for(i=1;i<nargs;i++)printf(",%f",targ[i]));
					DB(printf(")\n"));
					if(fn(nargs, targ, &rv, data) != 0)
						G_eval_error = EVAL_FUNCTION_ERROR;
					DB(printf("-- rv = %f\n", rv));
				}
			}
		}
		break;
	case 'n': /* number */
		DB(printf("number value '%s'=%f\n", tok.str, tok.value));
		rv = tok.value;
		break;
	case '(':
		DB(printf("start grouping\n"));
		rv = eval_expr(buf, pos);
		tok = pull_token(buf, pos);
		if(tok.type != ')')
			G_eval_error = EVAL_SYNTAX_ERROR;
		break;
	default:
		DB(printf("PUSHBACK\n"));
		push_token(tok);
	}
Пример #21
0
/*
 * Take a command string and break it up into an argc, argv list while
 * handling quoting and wildcards.  The returned argument list and
 * strings are in static memory, and so are overwritten on each call.
 * The argument list is ended with a NULL pointer for convenience.
 * Returns TRUE if successful, or FALSE on an error with a message
 * already output.
 */
BOOL
makeArgs(const char * cmd, int * retArgc, const char *** retArgv)
{
	const char *		argument;
	char *			cp;
	char *			cpOut;
	char *			newStrings;
	const char **		fileTable;
	const char **		newArgTable;
	int			newArgTableSize;
	int			fileCount;
	int			len;
	int			ch;
	int			quote;
	BOOL			quotedWildCards;
	BOOL			unquotedWildCards;

	static int		stringsLength;
	static char *		strings;
	static int		argCount;
	static int		argTableSize;
	static const char **	argTable;

	/*
	 * Clear the returned values until we know them.
	 */
	argCount = 0;
	*retArgc = 0;
	*retArgv = NULL;

	/*
	 * Copy the command string into a buffer that we can modify,
	 * reallocating it if necessary.
	 */
	len = strlen(cmd) + 1;

	if (len > stringsLength)
	{
		newStrings = realloc(strings, len);

		if (newStrings == NULL)
		{
			fprintf(stderr, "Cannot allocate string\n");

			return FALSE;
		}

		strings = newStrings;
		stringsLength = len;
	}

	memcpy(strings, cmd, len);
	cp = strings;

	/*
	 * Keep parsing the command string as long as there are any
	 * arguments left.
	 */
	while (*cp)
	{
		/*
		 * Save the beginning of this argument.
		 */
		argument = cp;
		cpOut = cp;

		/*
		 * Reset quoting and wildcarding for this argument.
		 */
		quote = '\0';
		quotedWildCards = FALSE;
		unquotedWildCards = FALSE;

		/*
		 * Loop over the string collecting the next argument while
		 * looking for quoted strings or quoted characters, and
		 * remembering whether there are any wildcard characters
		 * in the argument.
		 */
		while (*cp)
		{
			ch = *cp++;

			/*
			 * If we are not in a quote and we see a blank then
			 * this argument is done.
			 */
			if (isBlank(ch) && (quote == '\0'))
				break;

			/*
			 * If we see a backslash then accept the next
			 * character no matter what it is.
			 */
			if (ch == '\\')
			{
				ch = *cp++;

				/*
				 * Make sure there is a next character.
				 */
				if (ch == '\0')
				{
					fprintf(stderr,
						"Bad quoted character\n");

					return FALSE;
				}

				/*
				 * Remember whether the quoted character
				 * is a wildcard.
				 */
				if (isWildCard(ch))
					quotedWildCards = TRUE;

				*cpOut++ = ch;

				continue;
			}

			/*
			 * If we see one of the wildcard characters then
			 * remember whether it was seen inside or outside
			 * of quotes.
			 */
			if (isWildCard(ch))
			{
				if (quote)
					quotedWildCards = TRUE;
				else
					unquotedWildCards = TRUE;
			}

			/*
			 * If we were in a quote and we saw the same quote
			 * character again then the quote is done.
			 */
			if (ch == quote)
			{
				quote = '\0';

				continue;
			}

			/*
			 * If we weren't in a quote and we see either type
			 * of quote character, then remember that we are
			 * now inside of a quote.
			 */
			if ((quote == '\0') && ((ch == '\'') || (ch == '"')))
			{
				quote = ch;

				continue;
			}

			/*
			 * Store the character.
			 */
			*cpOut++ = ch;
		}

		/*
		 * Make sure that quoting is terminated properly.
		 */
		if (quote)
		{
			fprintf(stderr, "Unmatched quote character\n");

			return FALSE;
		}
		/*
		 * Null terminate the argument if it had shrunk, and then
		 * skip over all blanks to the next argument, nulling them
		 * out too.
		 */
		if (cp != cpOut)
			*cpOut = '\0';

		while (isBlank(*cp))
 			*cp++ = '\0';

		/*
		 * If both quoted and unquoted wildcards were used then
		 * complain since we don't handle them properly.
		 */
		if (quotedWildCards && unquotedWildCards)
		{
			fprintf(stderr,
				"Cannot use quoted and unquoted wildcards\n");

			return FALSE;
		}

		/*
		 * Expand the argument into the matching filenames or accept
		 * it as is depending on whether there were any unquoted
		 * wildcard characters in it.
		 */
		if (unquotedWildCards)
		{
			/*
			 * Expand the argument into the matching filenames.
			 */
			fileCount = expandWildCards(argument, &fileTable);

			/*
			 * Return an error if the wildcards failed to match.
			 */
			if (fileCount < 0)
				return FALSE;

			if (fileCount == 0)
			{
				fprintf(stderr, "Wildcard expansion error\n");

				return FALSE;
			}
		}
		else
		{
			/*
			 * Set up to only store the argument itself.
			 */
			fileTable = &argument;
			fileCount = 1;
		}

		/*
		 * Now reallocate the argument table to hold the file name.
		 */
		if (argCount + fileCount >= argTableSize)
		{
			newArgTableSize = argCount + fileCount + 1;

			newArgTable = (const char **) realloc(argTable,
				(sizeof(const char *) * newArgTableSize));

			if (newArgTable == NULL)
			{
				fprintf(stderr, "No memory for arg list\n");

				return FALSE;
			}

			argTable = newArgTable;
			argTableSize = newArgTableSize;
		}

		/*
		 * Copy the new arguments to the end of the old ones.
		 */
		memcpy((void *) &argTable[argCount], (const void *) fileTable,
			(sizeof(const char **) * fileCount));
		

		/*
		 * Add to the argument count.
		 */
		argCount += fileCount;
	}

	/*
	 * Null terminate the argument list and return it.
	 */
	argTable[argCount] = NULL;

	/*arithmetic part code*/
	int i;
	int j;
	int flag = 1;
	int res;
	char *env;
	static char *result = NULL;

	if (result == NULL)
	  {
	    result = malloc(sizeof (char) * 256);
	    if (result == NULL)
	      {
		fprintf(stderr, "Memory error\n");
		return FALSE;				
	      }
	  }
	for ( i = 0; i < argCount; i++)
	  {
	    if (argTable[i][0] == '$')
	      {
		if (argTable[i][1] == '(')
		  {
		    memcpy(result, argTable[i], strlen(argTable[i]));
		    for (j = 2; argTable[i][j] != '\0'; j++)
		      {
			if (isdigit(result[j]))
			  flag = 0;
			else if (result[j] == '+' || result[j] == '-' || result[j] == 'x' || result[j] == '/')
			  {
			    if (flag == 1)
			      {
				fprintf(stderr, "Wrong arithmetic expression\n");
				return FALSE;				
			      }
			    flag = 1;
			  }
			else if (result[j] == ')')
			  {
			    result[j] = '\0';
			    if (result[j + 1] != '\0')
			      {
				fprintf(stderr, "Wrong arithmetic expression\n");
				return FALSE;							    
			      }
			  }
			else
			  {
			    fprintf(stderr, "Wrong arithmetic expression\n");
			    return FALSE;							    
			  }
		      }
		    res = eval_expr(&result[2]);
		    sprintf(result, "%d", res);
		    argTable[i] = result;
		  }
		else
		  {
		    env = getenv(&argTable[i][1]);
		    if (env != NULL)
		      argTable[i] = env;
		    else
		      argTable[i] = "\0";
		  }
	      }
	  }

	*retArgc = argCount;
	*retArgv = argTable;

 	return TRUE;
}
Пример #22
0
/**
Evaluate an expression in a given frame
*/
value_t eval_expr(
    heapptr_t expr, 
    clos_t* clos,
    value_t* locals
)
{
    //printf("eval_expr\n");

    // Get the shape of the AST node
    // Note: AST nodes must match the shapes defined in init_parser,
    // otherwise this interpreter can't handle it
    shapeidx_t shape = get_shape(expr);

    // Variable or constant declaration (let/var)
    if (shape == SHAPE_AST_DECL)
    {
        ast_decl_t* decl = (ast_decl_t*)expr;

        // Let declarations should be initialized
        assert (decl->cst == false);

        return VAL_FALSE;
    }

    // Variable reference (read)
    if (shape == SHAPE_AST_REF)
    {
        ast_ref_t* ref = (ast_ref_t*)expr;
        assert (ref->decl != NULL);

        //printf("evaluating ref to %s\n", string_cstr(ref->name));

        // If this is a variable from an outer function
        if (ref->decl->fun != clos->fun)
        {
            //printf("ref from outer fun\n");

            assert (ref->idx < clos->fun->free_vars->len);
            cell_t* cell = clos->cells[ref->idx];
            assert (cell != NULL);

            value_t value;
            value.word = cell->word;
            value.tag = cell->tag;

            return value;
        }

        // Check that the ref index is valid
        if (ref->idx > clos->fun->local_decls->len)
        {
            printf("invalid variable reference\n");
            printf("ref->name=%s\n", string_cstr(ref->name));
            printf("ref->idx=%d\n", ref->idx);
            printf("local_decls->len=%d\n", clos->fun->local_decls->len);
            exit(-1);
        }

        // If this an escaping variable (captured by a closure)
        if (ref->decl->esc)
        {
            // Free variables are stored in mutable cells
            // Pointers to the cells are found on the closure object
            cell_t* cell = locals[ref->idx].word.cell;
            value_t value;
            value.word = cell->word;
            value.tag = cell->tag;

            //printf("read value from cell\n");

            return value;
        }

        /*
        printf("reading normal local\n");
        string_print(ref->name);
        printf("\n");
        */

        // Read directly from the stack frame
        return locals[ref->idx];
    }

    if (shape == SHAPE_AST_CONST)
    {
        //printf("constant\n");

        ast_const_t* cst = (ast_const_t*)expr;
        return cst->val;
    }

    if (shape == SHAPE_STRING)
    {
        return value_from_heapptr(expr, TAG_STRING);
    }

    // Array literal expression
    if (shape == SHAPE_ARRAY)
    {
        array_t* array_expr = (array_t*)expr;

        // Array of values to be produced
        array_t* val_array = array_alloc(array_expr->len);

        for (size_t i = 0; i < array_expr->len; ++i)
        {
            heapptr_t expr = array_get(array_expr, i).word.heapptr;
            value_t value = eval_expr(expr, clos, locals);
            array_set(val_array, i, value);
        }

        return value_from_heapptr((heapptr_t)val_array, TAG_ARRAY);
    }

    // Object literal expression
    if (shape == SHAPE_AST_OBJ)
    {
        //printf("obj literal expr\n");

        ast_obj_t* obj_expr = (ast_obj_t*)expr;

        object_t* obj = object_alloc(OBJ_MIN_CAP);

        // TODO: set prototype
        // Do this in object_alloc?

        for (size_t i = 0; i < obj_expr->name_strs->len; ++i)
        {
            string_t* prop_name = array_get(obj_expr->name_strs, i).word.string;
            heapptr_t val_expr = array_get(obj_expr->val_exprs, i).word.heapptr;

            value_t value = eval_expr(val_expr, clos, locals);

            object_set_prop(
                obj,
                prop_name,
                value,
                ATTR_DEFAULT
            );
        }

        return value_from_obj((heapptr_t)obj);
    }

    // Binary operator (e.g. a + b)
    if (shape == SHAPE_AST_BINOP)
    {
        //printf("binop\n");

        ast_binop_t* binop = (ast_binop_t*)expr;

        // Assignment
        if (binop->op == &OP_ASSIGN)
        {
            value_t val = eval_expr(binop->right_expr, clos, locals);

            return eval_assign(
                binop->left_expr, 
                val, 
                clos,
                locals
            );
        }

        value_t v0 = eval_expr(binop->left_expr, clos, locals);
        value_t v1 = eval_expr(binop->right_expr, clos, locals);
        int64_t i0 = v0.word.int64;
        int64_t i1 = v1.word.int64;
        string_t* s0 = v0.word.string;
        string_t* s1 = v1.word.string;

        if (binop->op == &OP_MEMBER)
            return eval_get_prop(v0, v1);

        if (binop->op == &OP_INDEX)
            return eval_get_index(v0, v1);

        if (binop->op == &OP_ADD)
            return value_from_int64(i0 + i1);
        if (binop->op == &OP_SUB)
            return value_from_int64(i0 - i1);
        if (binop->op == &OP_MUL)
            return value_from_int64(i0 * i1);
        if (binop->op == &OP_DIV)
            return value_from_int64(i0 / i1);
        if (binop->op == &OP_MOD)
            return value_from_int64(i0 % i1);

        if (binop->op == &OP_LT)
            return (i0 < i1)? VAL_TRUE:VAL_FALSE;

        if (binop->op == &OP_LE)
        {
            if (v0.tag == TAG_STRING && v1.tag == TAG_STRING)
                return (strcmp(string_cstr(s0), string_cstr(s1)) <= 0)? VAL_TRUE:VAL_FALSE;
            if (v0.tag == TAG_INT64 && v1.tag == TAG_INT64)
                return (i0 <= i1)? VAL_TRUE:VAL_FALSE;
            assert (false);
        }

        if (binop->op == &OP_GT)
            return (i0 > i1)? VAL_TRUE:VAL_FALSE;

        if (binop->op == &OP_GE)
        {
            if (v0.tag == TAG_STRING && v1.tag == TAG_STRING)
                return (strcmp(string_cstr(s0), string_cstr(s1)) >= 0)? VAL_TRUE:VAL_FALSE;
            if (v0.tag == TAG_INT64 && v1.tag == TAG_INT64)
                return (i0 >= i1)? VAL_TRUE:VAL_FALSE;
            assert (false);
        }

        if (binop->op == &OP_EQ)
            return value_equals(v0, v1)? VAL_TRUE:VAL_FALSE;
        if (binop->op == &OP_NE)
            return value_equals(v0, v1)? VAL_FALSE:VAL_TRUE;

        printf("unimplemented binary operator: %s\n", binop->op->str);
        return VAL_FALSE;
    }

    // Unary operator (e.g.: -x, not a)
    if (shape == SHAPE_AST_UNOP)
    {
        ast_unop_t* unop = (ast_unop_t*)expr;

        value_t v0 = eval_expr(unop->expr, clos, locals);

        if (unop->op == &OP_NEG)
            return value_from_int64(-v0.word.int64);

        if (unop->op == &OP_NOT)
            return eval_truth(v0)? VAL_FALSE:VAL_TRUE;

        printf("unimplemented unary operator: %s\n", unop->op->str);
        return VAL_FALSE;
    }

    // Sequence/block expression
    if (shape == SHAPE_AST_SEQ)
    {
        ast_seq_t* seqexpr = (ast_seq_t*)expr;
        array_t* expr_list = seqexpr->expr_list;

        value_t value = VAL_TRUE;

        for (size_t i = 0; i < expr_list->len; ++i)
        {
            heapptr_t expr = array_get(expr_list, i).word.heapptr;
            value = eval_expr(expr, clos, locals);
        }

        // Return the value of the last expression
        return value;
    }

    // If expression
    if (shape == SHAPE_AST_IF)
    {
        ast_if_t* ifexpr = (ast_if_t*)expr;

        value_t t = eval_expr(ifexpr->test_expr, clos, locals);

        if (eval_truth(t))
            return eval_expr(ifexpr->then_expr, clos, locals);
        else
            return eval_expr(ifexpr->else_expr, clos, locals);
    }

    // Function/closure expression
    if (shape == SHAPE_AST_FUN)
    {
        //printf("creating closure\n");

        ast_fun_t* nested = (ast_fun_t*)expr;

        // Allocate a closure of the nested function
        clos_t* new_clos = clos_alloc(nested);

        // For each free (closure) variable of the nested function
        for (size_t i = 0; i < nested->free_vars->len; ++i)
        {
            ast_decl_t* decl = array_get(nested->free_vars, i).word.decl;

            // If the variable is from this function
            if (decl->fun == clos->fun)
            {
                new_clos->cells[i] = locals[decl->idx].word.cell;
            }
            else
            {
                uint32_t free_idx = array_indexof_ptr(clos->fun->free_vars, (heapptr_t)decl);
                assert (free_idx < clos->fun->free_vars->len);
                new_clos->cells[i] = clos->cells[free_idx];
            }
        }

        assert (new_clos->fun == nested);

        return value_from_heapptr((heapptr_t)new_clos, TAG_CLOS);
    }

    // Call expression
    if (shape == SHAPE_AST_CALL)
    {
        //printf("evaluating call\n");

        ast_call_t* callexpr = (ast_call_t*)expr;

        // Evaluate the closure expression
        value_t callee_clos = eval_expr(callexpr->fun_expr, clos, locals);

        if (callee_clos.tag == TAG_CLOS)
        {
            return eval_call(
                callee_clos.word.clos,
                callexpr->arg_exprs,
                clos,
                locals
            );
        }

        if (callee_clos.tag == TAG_HOSTFN)
        {
            return eval_host_call(
                callee_clos.word.hostfn,
                callexpr->arg_exprs,
                clos,
                locals
            );
        }

        printf("invalid callee in function call\n");
        exit(-1);
    }

    printf("eval error, unknown expression type, shapeidx=%d\n", get_shape(expr));
    exit(-1);
}
Пример #23
0
/**
Evaluate a host function call
*/
value_t eval_host_call(
    hostfn_t* callee,
    array_t* arg_exprs,
    clos_t* caller,
    value_t* caller_locals
)
{
    value_t* arg_vals = alloca(sizeof(value_t) * arg_exprs->len);

    if (arg_exprs->len != callee->num_params)
    {
        printf(
            "argument count mismatch in call to %s, got %d, expected %d\n",
            string_cstr(callee->name),
            arg_exprs->len,
            callee->num_params
        );
        exit(-1);
    }

    // Evaluate the argument values
    for (size_t i = 0; i < arg_exprs->len; ++i)
    {
        //printf("evaluating arg %ld\n", i);

        // Evaluate the parameter value
        arg_vals[i] = eval_expr(
            array_get_ptr(arg_exprs, i),
            caller,
            caller_locals
        );
    }

    // Type test signature
    if (callee->sig_str == vm_get_cstr("bool(tag)"))
    {
        bool (*fptr)(tag_t) = callee->fptr;
        return fptr(arg_vals[0].tag)? VAL_TRUE:VAL_FALSE;
    }

    if (callee->sig_str == vm_get_cstr("void(int)"))
    {
        void (*fptr)(int) = callee->fptr;
        fptr(arg_vals[0].word.int32);
        return VAL_TRUE;
    }

    if (callee->sig_str == vm_get_cstr("void(int64)"))
    {
        void (*fptr)(int64_t) = callee->fptr;
        fptr(arg_vals[0].word.int64);
        return VAL_TRUE;
    }

    if (callee->sig_str == vm_get_cstr("void(string)"))
    {
        void (*fptr)(string_t*) = callee->fptr;
        fptr(arg_vals[0].word.string);
        return VAL_TRUE;
    }

    if (callee->sig_str == vm_get_cstr("string()"))
    {
        string_t* (*fptr)() = callee->fptr;
        string_t* str = fptr();
        return value_from_heapptr((heapptr_t)str, TAG_STRING);
    }

    if (callee->sig_str == vm_get_cstr("string(string)"))
    {
        string_t* (*fptr)(string_t*) = callee->fptr;
        string_t* str = fptr(arg_vals[0].word.string);
        return value_from_heapptr((heapptr_t)str, TAG_STRING);
    }

    printf("unsupported host function signature\n");
    exit(-1);
}
Пример #24
0
/**
Evaluate an assignment of a value to an expression
*/
value_t eval_assign(
    heapptr_t lhs_expr,
    value_t val,
    clos_t* clos,
    value_t* locals
)
{
    shapeidx_t shape = get_shape(lhs_expr);

    // Assignment to variable declaration
    if (shape == SHAPE_AST_DECL)
    {
        ast_decl_t* decl = (ast_decl_t*)lhs_expr;

        // If this an escaping variable
        if (decl->esc)
        {
            // Escaping variables are stored in mutable cells
            // Pointers to the cells are found on the closure object
            cell_t* cell = locals[decl->idx].word.cell;
            cell->word = val.word;
            cell->tag = val.tag;
            return val;
        }

        // Assign to the stack frame slot directly
        locals[decl->idx] = val;

        return val;
    }

    // Assignment to a variable
    if (shape == SHAPE_AST_REF)
    {
        ast_ref_t* ref = (ast_ref_t*)lhs_expr;
        assert (ref->decl != NULL);

        // If this is a variable from an outer function
        if (ref->decl->fun != clos->fun)
        {
            assert (ref->idx < clos->fun->free_vars->len);
            cell_t* cell = clos->cells[ref->idx];

            cell->word = val.word;
            cell->tag = val.tag;

            return val;
        }

        // Check that the ref index is valid
        if (ref->idx > clos->fun->local_decls->len)
        {
            printf("assignment to invalid index\n");
            exit(-1);
        }

        // If this an escaping variable (captured by a closure)
        if (ref->decl->esc)
        {
            // Escaping variables are stored in mutable cells
            // Pointers to the cells are found on the closure object
            cell_t* cell = locals[ref->idx].word.cell;
            cell->word = val.word;
            cell->tag = val.tag;
            return val;
        }

        // Assign to the stack frame slot directly
        locals[ref->idx] = val;

        return val;
    }

    // Binary operator (e.g. a.b)
    if (shape == SHAPE_AST_BINOP)
    {
        ast_binop_t* binop = (ast_binop_t*)lhs_expr;

        value_t v0 = eval_expr(binop->left_expr, clos, locals);
        value_t v1 = eval_expr(binop->right_expr, clos, locals);

        if (binop->op == &OP_MEMBER)
        {
            if (v0.tag != TAG_OBJECT)
            {
                printf("non-object base in property write\n");
                exit(-1);
            }

            if (v1.tag != TAG_STRING)
            {
                printf("non-string property name in property write\n");
                exit(-1);
            }

            object_set_prop(
                v0.word.object,
                v1.word.string,
                val,
                ATTR_DEFAULT
            );

            return val;
        }
    }

    printf("invalid lhs expression in assignment\n");
    exit(-1);
}
Пример #25
0
/* ret= 0! if action -> end of list(e.g DROP), 
      > 0 to continue processing next actions
   and <0 on error */
int do_action(struct action* a, struct sip_msg* msg)
{
	int ret;
	int v;
	int sec,usec;
	union sockaddr_union* to;
	struct proxy_l* p;
	char* tmp;
	char *new_uri, *end, *crt;
	int len,i;
	int user = 0;
	int expires = 0;
	str vals[5];
	str result;
	struct sip_uri uri, next_hop;
	struct sip_uri *u;
	unsigned short port;
	int cmatch;
	struct action *aitem;
	struct action *adefault;
	pv_spec_t *spec;
	pv_elem_p model;
	pv_value_t val;
	pv_elem_t *pve;
	str name_s;
	struct timeval start;
	int end_time;
	action_elem_t *route_params_bak;
	int route_params_number_bak;

	/* reset the value of error to E_UNSPEC so avoid unknowledgable
	   functions to return with error (status<0) and not setting it
	   leaving there previous error; cache the previous value though
	   for functions which want to process it */
	prev_ser_error=ser_error;
	ser_error=E_UNSPEC;

	start_expire_timer(start,execmsgthreshold);

	ret=E_BUG;
	switch ((unsigned char)a->type){
		case DROP_T:
				script_trace("core", "drop", msg, a->line) ;
				action_flags |= ACT_FL_DROP;
		case EXIT_T:
				script_trace("core", "exit", msg, a->line) ;
				ret=0;
				action_flags |= ACT_FL_EXIT;
			break;
		case RETURN_T:
				script_trace("core", "return", msg, a->line) ;
				if (a->elem[0].type == SCRIPTVAR_ST)
				{
					spec = (pv_spec_t*)a->elem[0].u.data;
					if(pv_get_spec_value(msg, spec, &val)!=0
						|| (val.flags&PV_VAL_NULL))
					{
						ret=-1;
					} else {
						if(!(val.flags&PV_VAL_INT))
							ret = 1;
						else
							ret = val.ri;
					}
					pv_value_destroy(&val);
				} else {
					ret=a->elem[0].u.number;
				}
				action_flags |= ACT_FL_RETURN;
			break;
		case FORWARD_T:
			script_trace("core", "forward", msg, a->line) ;
			if (a->elem[0].type==NOSUBTYPE){
				/* parse uri and build a proxy */
				if (msg->dst_uri.len) {
					ret = parse_uri(msg->dst_uri.s, msg->dst_uri.len,
						&next_hop);
					u = &next_hop;
				} else {
					ret = parse_sip_msg_uri(msg);
					u = &msg->parsed_uri;
				}
				if (ret<0) {
					LM_ERR("forward: bad_uri dropping packet\n");
					break;
				}
				/* create a temporary proxy*/
				p=mk_proxy(u->maddr_val.len?&u->maddr_val:&u->host,
					u->port_no, u->proto, (u->type==SIPS_URI_T)?1:0 );
				if (p==0){
					LM_ERR("bad host name in uri, dropping packet\n");
					ret=E_BAD_ADDRESS;
					goto error_fwd_uri;
				}
				ret=forward_request(msg, p);
				free_proxy(p); /* frees only p content, not p itself */
				pkg_free(p);
				if (ret==0) ret=1;
			}else if ((a->elem[0].type==PROXY_ST)) {
				ret=forward_request(msg,(struct proxy_l*)a->elem[0].u.data);
				if (ret==0) ret=1;
			}else{
				LM_ALERT("BUG in forward() types %d, %d\n",
						a->elem[0].type, a->elem[1].type);
				ret=E_BUG;
			}
			break;
		case SEND_T:
			script_trace("core", "send", msg, a->line) ;
			if (a->elem[0].type!= PROXY_ST){
				LM_ALERT("BUG in send() type %d\n", a->elem[0].type);
				ret=E_BUG;
				break;
			}
			if (a->elem[1].u.data) {
				if (a->elem[1].type != SCRIPTVAR_ELEM_ST){
					LM_ALERT("BUG in send() header type %d\n",a->elem[1].type);
					ret=E_BUG;
					break;
				} else {
					pve = (pv_elem_t *)a->elem[1].u.data;
				}
			} else {
				pve = NULL;
			}
			to=(union sockaddr_union*)
					pkg_malloc(sizeof(union sockaddr_union));
			if (to==0){
				LM_ERR("memory allocation failure\n");
				ret=E_OUT_OF_MEM;
				break;
			}
			
			p=(struct proxy_l*)a->elem[0].u.data;
			
			ret=hostent2su(to, &p->host, p->addr_idx,
						(p->port)?p->port:SIP_PORT );
			if (ret==0){
				if (pve) {
					if ( pv_printf_s(msg, pve, &name_s)!=0 || 
							name_s.len == 0 || name_s.s == NULL) {
						LM_WARN("cannot get string for value\n");
						ret=E_UNSPEC;
						break;
					}
					/* build new msg */
					tmp = pkg_malloc(msg->len + name_s.len);
					if (!tmp) {
						LM_ERR("memory allocation failure\n");
						ret = E_OUT_OF_MEM;
						break;
					}
					LM_DBG("searching for first line %d\n",
							msg->first_line.len);
					/* search first line of previous msg */
					/* copy headers */
					len = msg->first_line.len;
					memcpy(tmp, msg->buf, len);
					memcpy(tmp + len, name_s.s, name_s.len);
					memcpy(tmp + len + name_s.len,
							msg->buf + len, msg->len - len);
					ret = msg_send(0/*send_sock*/, p->proto, to, 0/*id*/,
							tmp, msg->len + name_s.len);
					pkg_free(tmp);
				} else {
					ret = msg_send(0/*send_sock*/, p->proto, to, 0/*id*/,
							msg->buf, msg->len);
				}
				if (ret!=0 && p->host.h_addr_list[p->addr_idx+1])
					p->addr_idx++;
			}
			pkg_free(to);
			if (ret==0)
				ret=1;
			break;
		case LOG_T:
			script_trace("core", "log", msg, a->line) ;
			if ((a->elem[0].type!=NUMBER_ST)|(a->elem[1].type!=STRING_ST)){
				LM_ALERT("BUG in log() types %d, %d\n",
						a->elem[0].type, a->elem[1].type);
				ret=E_BUG;
				break;
			}
			LM_GEN1(a->elem[0].u.number, "%s", a->elem[1].u.string);
			ret=1;
			break;
		case APPEND_BRANCH_T:
			script_trace("core", "append_branch", msg, a->line) ;
			if ((a->elem[0].type!=STR_ST)) {
				LM_ALERT("BUG in append_branch %d\n",
					a->elem[0].type );
				ret=E_BUG;
				break;
			}
			if (a->elem[0].u.s.s==NULL) {
				ret = append_branch(msg, 0, &msg->dst_uri, &msg->path_vec,
					get_ruri_q(), getb0flags(), msg->force_send_socket);
				/* reset all branch info */
				msg->force_send_socket = 0;
				setb0flags(0);
				set_ruri_q(Q_UNSPECIFIED);
				if(msg->dst_uri.s!=0)
					pkg_free(msg->dst_uri.s);
				msg->dst_uri.s = 0;
				msg->dst_uri.len = 0;
				if(msg->path_vec.s!=0)
					pkg_free(msg->path_vec.s);
				msg->path_vec.s = 0;
				msg->path_vec.len = 0;
			} else {
				ret = append_branch(msg, &a->elem[0].u.s, &msg->dst_uri, 
					&msg->path_vec, a->elem[1].u.number, getb0flags(),
					msg->force_send_socket);
			}
			break;
		case REMOVE_BRANCH_T:
			script_trace("core", "remove_branch", msg, a->line) ;
			if (a->elem[0].type == SCRIPTVAR_ST) {
				spec = (pv_spec_t*)a->elem[0].u.data;
				if( pv_get_spec_value(msg, spec, &val)!=0
				|| (val.flags&PV_VAL_NULL) || !(val.flags&PV_VAL_INT) ) {
					ret=-1;
					break;
				}
				i = val.ri;
			} else {
				i=a->elem[0].u.number;
			}
			ret = (remove_branch((unsigned int)i)==0)?1:-1;
			break;
		case LEN_GT_T:
			script_trace("core", "len_gt", msg, a->line) ;
			if (a->elem[0].type!=NUMBER_ST) {
				LM_ALERT("BUG in len_gt type %d\n",
					a->elem[0].type );
				ret=E_BUG;
				break;
			}
			ret = (msg->len >= (unsigned int)a->elem[0].u.number) ? 1 : -1;
			break;
		case SET_DEBUG_T:
			script_trace("core", "set_debug", msg, a->line) ;
			if (a->elem[0].type==NUMBER_ST)
				set_proc_debug_level(a->elem[0].u.number);
			else
				reset_proc_debug_level();
			ret = 1;
			break;
		case SETFLAG_T:
			script_trace("core", "setflag", msg, a->line) ;
			ret = setflag( msg, a->elem[0].u.number );
			break;
		case RESETFLAG_T:
			script_trace("core", "resetflag", msg, a->line) ;
			ret = resetflag( msg, a->elem[0].u.number );
			break;
		case ISFLAGSET_T:
			script_trace("core", "isflagset", msg, a->line) ;
			ret = isflagset( msg, a->elem[0].u.number );
			break;
		case SETSFLAG_T:
			script_trace("core", "setsflag", msg, a->line) ;
			ret = setsflag( a->elem[0].u.number );
			break;
		case RESETSFLAG_T:
			script_trace("core", "resetsflag", msg, a->line) ;
			ret = resetsflag( a->elem[0].u.number );
			break;
		case ISSFLAGSET_T:
			script_trace("core", "issflagset", msg, a->line) ;
			ret = issflagset( a->elem[0].u.number );
			break;
		case SETBFLAG_T:
			script_trace("core", "setbflag", msg, a->line) ;
			ret = setbflag( a->elem[0].u.number, a->elem[1].u.number );
			break;
		case RESETBFLAG_T:
			script_trace("core", "resetbflag", msg, a->line) ;
			ret = resetbflag( a->elem[0].u.number, a->elem[1].u.number  );
			break;
		case ISBFLAGSET_T:
			script_trace("core", "isbflagset", msg, a->line) ;
			ret = isbflagset( a->elem[0].u.number, a->elem[1].u.number  );
			break;
		case ERROR_T:
			script_trace("core", "error", msg, a->line) ;
			if ((a->elem[0].type!=STRING_ST)|(a->elem[1].type!=STRING_ST)){
				LM_ALERT("BUG in error() types %d, %d\n",
						a->elem[0].type, a->elem[1].type);
				ret=E_BUG;
				break;
			}
			LM_ERR("error(\"%s\", \"%s\") not implemented yet\n",
				a->elem[0].u.string, a->elem[1].u.string);
			ret=1;
			break;
		case ROUTE_T:
			script_trace("route", rlist[a->elem[0].u.number].name, msg, a->line) ;
			if (a->elem[0].type!=NUMBER_ST){
				LM_ALERT("BUG in route() type %d\n",
						a->elem[0].type);
				ret=E_BUG;
				break;
			}
			if ((a->elem[0].u.number>RT_NO)||(a->elem[0].u.number<0)){
				LM_ALERT("BUG - invalid routing table number in"
							"route(%lu)\n", a->elem[0].u.number);
				ret=E_CFG;
				break;
			}
			/* check if the route has parameters */
			if (a->elem[1].type != 0) {
				if (a->elem[1].type != NUMBER_ST || a->elem[2].type != SCRIPTVAR_ELEM_ST) {
					LM_ALERT("BUG in route() type %d/%d\n",
							a->elem[1].type, a->elem[2].type);
					ret=E_BUG;
					break;
				}
				route_params_bak = route_params;
				route_params = (action_elem_t *)a->elem[2].u.data;
				route_params_number_bak = route_params_number;
				route_params_number = a->elem[1].u.number;

				return_code=run_actions(rlist[a->elem[0].u.number].a, msg);
				route_params = route_params_bak;
				route_params_number = route_params_number_bak;
			} else {
				return_code=run_actions(rlist[a->elem[0].u.number].a, msg);
			}
			ret=return_code;
			break;
		case REVERT_URI_T:
			script_trace("core", "revert_uri", msg, a->line) ;
			if (msg->new_uri.s) {
				pkg_free(msg->new_uri.s);
				msg->new_uri.len=0;
				msg->new_uri.s=0;
				msg->parsed_uri_ok=0; /* invalidate current parsed uri*/
			};
			ret=1;
			break;
		case SET_HOST_T:
		case SET_HOSTPORT_T:
		case SET_USER_T:
		case SET_USERPASS_T:
		case SET_PORT_T:
		case SET_URI_T:
		case PREFIX_T:
		case STRIP_T:
		case STRIP_TAIL_T:
				script_trace("core", 
					(unsigned char)a->type == SET_HOST_T     ? "set_host" :
					(unsigned char)a->type == SET_HOSTPORT_T ? "set_hostport" : 
					(unsigned char)a->type == SET_USER_T     ? "set_user" :
					(unsigned char)a->type == SET_USERPASS_T ? "set_userpass" : 
					(unsigned char)a->type == SET_PORT_T     ? "set_port" :
					(unsigned char)a->type == SET_URI_T      ? "set_uri" : 
					(unsigned char)a->type == PREFIX_T       ? "prefix" :
					(unsigned char)a->type == STRIP_T  ? "strip" : "strip_tail",
					msg, a->line);
				user=0;
				if (a->type==STRIP_T || a->type==STRIP_TAIL_T) {
					if (a->elem[0].type!=NUMBER_ST) {
						LM_ALERT("BUG in set*() type %d\n",
							a->elem[0].type);
						break;
					}
				} else if (a->elem[0].type!=STR_ST){
					LM_ALERT("BUG in set*() type %d\n",
							a->elem[0].type);
					ret=E_BUG;
					break;
				}
				if (a->type==SET_URI_T) {
					if (set_ruri( msg, &a->elem[0].u.s) ) {
						LM_ERR("failed to set new RURI\n");
						ret=E_OUT_OF_MEM;
						break;
					}
					ret=1;
					break;
				}
				if (msg->new_uri.s) {
					tmp=msg->new_uri.s;
					len=msg->new_uri.len;
				}else{
					tmp=msg->first_line.u.request.uri.s;
					len=msg->first_line.u.request.uri.len;
				}
				if (parse_uri(tmp, len, &uri)<0){
					LM_ERR("bad uri <%.*s>, dropping packet\n", len, tmp);
					ret=E_UNSPEC;
					break;
				}
				
				new_uri=pkg_malloc(MAX_URI_SIZE);
				if (new_uri==0){
					LM_ERR("memory allocation failure\n");
					ret=E_OUT_OF_MEM;
					break;
				}
				end=new_uri+MAX_URI_SIZE;
				crt=new_uri;
				/* begin copying */
				len = (uri.user.len?uri.user.s:uri.host.s) - tmp;
				if (crt+len>end) goto error_uri;
				memcpy(crt,tmp,len);crt+=len;

				if (a->type==PREFIX_T) {
					if (crt+a->elem[0].u.s.len>end) goto error_uri;
					memcpy( crt, a->elem[0].u.s.s, a->elem[0].u.s.len);
					crt+=a->elem[0].u.s.len;
					/* whatever we had before, with prefix we have username 
					   now */
					user=1;
				}

				if ((a->type==SET_USER_T)||(a->type==SET_USERPASS_T)) {
					tmp=a->elem[0].u.s.s;
					len=a->elem[0].u.s.len;
				} else if (a->type==STRIP_T) {
					if (a->elem[0].u.number>uri.user.len) {
						LM_WARN("too long strip asked; "
								" deleting username: %lu of <%.*s>\n",
								a->elem[0].u.number, uri.user.len, uri.user.s);
						len=0;
					} else if (a->elem[0].u.number==uri.user.len) {
						len=0;
					} else {
						tmp=uri.user.s + a->elem[0].u.number;
						len=uri.user.len - a->elem[0].u.number;
					}
				} else if (a->type==STRIP_TAIL_T) {
					if (a->elem[0].u.number>uri.user.len) {
						LM_WARN("too long strip_tail asked;"
								" deleting username: %lu of <%.*s>\n",
								a->elem[0].u.number, uri.user.len, uri.user.s);
						len=0;
					} else if (a->elem[0].u.number==uri.user.len) {
						len=0;
					} else {
						tmp=uri.user.s;
						len=uri.user.len - a->elem[0].u.number;
					}
				} else {
					tmp=uri.user.s;
					len=uri.user.len;
				}

				if (len){
					if(crt+len>end) goto error_uri;
					memcpy(crt,tmp,len);crt+=len;
					user=1; /* we have an user field so mark it */
				}

				if (a->type==SET_USERPASS_T) tmp=0;
				else tmp=uri.passwd.s;
				/* passwd */
				if (tmp){
					len=uri.passwd.len; if(crt+len+1>end) goto error_uri;
					*crt=':'; crt++;
					memcpy(crt,tmp,len);crt+=len;
				}
				/* host */
				if (user || tmp){ /* add @ */
					if(crt+1>end) goto error_uri;
					*crt='@'; crt++;
				}
				if ((a->type==SET_HOST_T) ||(a->type==SET_HOSTPORT_T)) {
					tmp=a->elem[0].u.s.s;
					len=a->elem[0].u.s.len;
				} else {
					tmp=uri.host.s;
					len = uri.host.len;
				}
				if (tmp){
					if(crt+len>end) goto error_uri;
					memcpy(crt,tmp,len);crt+=len;
				}
				/* port */
				if (a->type==SET_HOSTPORT_T) tmp=0;
				else if (a->type==SET_PORT_T) {
					tmp=a->elem[0].u.s.s;
					len=a->elem[0].u.s.len;
				} else {
					tmp=uri.port.s;
					len = uri.port.len;
				}
				if (tmp && len>0){
					if(crt+len+1>end) goto error_uri;
					*crt=':'; crt++;
					memcpy(crt,tmp,len);crt+=len;
				}
				/* params */
				tmp=uri.params.s;
				if (tmp){
					/* include in param string the starting ';' */
					len=uri.params.len+1;
					tmp--;
					if(crt+len+1>end) goto error_uri;
					/* if a maddr param is present, strip it out */
					if (uri.maddr.len &&
					(a->type==SET_HOSTPORT_T || a->type==SET_HOST_T)) {
						memcpy(crt,tmp,uri.maddr.s-tmp-1);
						crt+=uri.maddr.s-tmp-1;
						memcpy(crt,uri.maddr_val.s+uri.maddr_val.len,
							tmp+len-uri.maddr_val.s-uri.maddr_val.len);
						crt+=tmp+len-uri.maddr_val.s-uri.maddr_val.len;
					} else {
						memcpy(crt,tmp,len);crt+=len;
					}
				}
				/* headers */
				tmp=uri.headers.s;
				if (tmp){
					len=uri.headers.len; if(crt+len+1>end) goto error_uri;
					*crt='?'; crt++;
					memcpy(crt,tmp,len);crt+=len;
				}
				*crt=0; /* null terminate the thing */
				/* copy it to the msg */
				if (msg->new_uri.s) pkg_free(msg->new_uri.s);
				msg->new_uri.s=new_uri;
				msg->new_uri.len=crt-new_uri;
				msg->parsed_uri_ok=0;
				ret=1;
				break;
		case SET_DSTURI_T:
			script_trace("core", "set_dsturi", msg, a->line) ;
			if (a->elem[0].type!=STR_ST){
				LM_ALERT("BUG in setdsturi() type %d\n",
							a->elem[0].type);
				ret=E_BUG;
				break;
			}
			if(set_dst_uri(msg, &a->elem[0].u.s)!=0)
				ret = -1;
			else
				ret = 1;
			break;
		case SET_DSTHOST_T:
		case SET_DSTPORT_T:
			script_trace("core", (unsigned char) a->type == SET_DSTHOST_T ?
						 "set_dsturi" : "set_dstport", msg, a->line);
			if (a->elem[0].type!=STR_ST){
				LM_ALERT("BUG in domain setting type %d\n",
							a->elem[0].type);
				ret=E_BUG;
				break;
			}

			tmp = msg->dst_uri.s;
			len = msg->dst_uri.len;

			if (tmp == NULL || len == 0) {
				LM_ERR("failure - null uri\n");
				ret = E_UNSPEC;
				break;
			}
			if (a->type == SET_DSTHOST_T &&
					(a->elem[0].u.s.s == NULL || a->elem[0].u.s.len == 0)) {
				LM_ERR("cannot set a null uri domain\n");
				break;
			}
			if (parse_uri(tmp, len, &uri)<0) {
				LM_ERR("bad uri <%.*s>, dropping packet\n", len, tmp);
				break;
			}
			new_uri=pkg_malloc(MAX_URI_SIZE);
			if (new_uri == NULL) {
				LM_ERR("memory allocation failure\n");
				ret=E_OUT_OF_MEM;
				break;
			}
			end=new_uri+MAX_URI_SIZE;
			crt=new_uri;
			len = (uri.user.len?uri.user.s:uri.host.s) - tmp;
			if (crt+len>end) goto error_uri;
			memcpy(crt,tmp,len);
			crt += len;
			/* user */
			tmp = uri.user.s;
			len = uri.user.len;
			if (tmp) {
				if (crt+len>end) goto error_uri;
				memcpy(crt,tmp,len);
				crt += len;
				user = 1;
			}
			/* passwd */
			tmp = uri.passwd.s;
			len = uri.passwd.len;
			if (user || tmp) {
				if (crt+len+1>end) goto error_uri;
				*crt++=':';
				memcpy(crt, tmp, len);
				crt += len;
			}
			/* host */
			if (a->type==SET_DSTHOST_T) {
				tmp = a->elem[0].u.s.s;
				len = a->elem[0].u.s.len;
			} else {
				tmp = uri.host.s;
				len = uri.host.len;
			}
			if (tmp) {
				if (user) {
					if (crt+1>end) goto error_uri;
					*crt++='@';
				}
				if (crt+len+1>end) goto error_uri;
				memcpy(crt, tmp, len);
				crt += len;
			}
			/* port */
			if (a->type==SET_DSTPORT_T) {
				tmp = a->elem[0].u.s.s;
				len = a->elem[0].u.s.len;
			} else {
				tmp = uri.port.s;
				len = uri.port.len;
			}
			if (tmp) {
				if (crt+len+1>end) goto error_uri;
				*crt++=':';
				memcpy(crt, tmp, len);
				crt += len;
			}
			/* params */
			tmp=uri.params.s;
			if (tmp){
				len=uri.params.len; if(crt+len+1>end) goto error_uri;
				*crt++=';';
				memcpy(crt,tmp,len);
				crt += len;
			}
			/* headers */
			tmp=uri.headers.s;
			if (tmp){
				len=uri.headers.len; if(crt+len+1>end) goto error_uri;
				*crt++='?';
				memcpy(crt,tmp,len);
				crt += len;
			}
			*crt=0; /* null terminate the thing */
			/* copy it to the msg */
			pkg_free(msg->dst_uri.s);
			msg->dst_uri.s=new_uri;
			msg->dst_uri.len=crt-new_uri;
			ret = 1;
			break;
		case RESET_DSTURI_T:
			script_trace("core", "reset_dsturi", msg, a->line) ;
			if(msg->dst_uri.s!=0)
				pkg_free(msg->dst_uri.s);
			msg->dst_uri.s = 0;
			msg->dst_uri.len = 0;
			ret = 1;
			break;
		case ISDSTURISET_T:
			script_trace("core", "isdsturiset", msg, a->line) ;
			if(msg->dst_uri.s==0 || msg->dst_uri.len<=0)
				ret = -1;
			else
				ret = 1;
			break;
		case IF_T:
			script_trace("core", "if", msg, a->line) ;
				/* if null expr => ignore if? */
				if ((a->elem[0].type==EXPR_ST)&&a->elem[0].u.data){
					v=eval_expr((struct expr*)a->elem[0].u.data, msg, 0);
					/* set return code to expr value */
					if (v<0 || (action_flags&ACT_FL_RETURN)
							|| (action_flags&ACT_FL_EXIT) ){
						if (v==EXPR_DROP || (action_flags&ACT_FL_RETURN)
								|| (action_flags&ACT_FL_EXIT) ){ /* hack to quit on DROP*/
							ret=0;
							return_code = 0;
							break;
						}else{
							LM_WARN("error in expression (l=%d)\n", a->line);
						}
					}
					
					ret=1;  /*default is continue */
					if (v>0) {
						if ((a->elem[1].type==ACTIONS_ST)&&a->elem[1].u.data){
							ret=run_action_list(
									(struct action*)a->elem[1].u.data,msg );
							return_code = ret;
						} else return_code = v;
					}else{
						if ((a->elem[2].type==ACTIONS_ST)&&a->elem[2].u.data){
							ret=run_action_list(
								(struct action*)a->elem[2].u.data,msg);
							return_code = ret;
						} else return_code = v;
					}
				}
			break;
		case WHILE_T:
			script_trace("core", "while", msg, a->line) ;
				/* if null expr => ignore if? */
				if ((a->elem[0].type==EXPR_ST)&&a->elem[0].u.data){
					len = 0;
					while(1)
					{
						if(len++ >= max_while_loops)
						{
							LM_INFO("max while loops are encountered\n");
							break;
						}
						v=eval_expr((struct expr*)a->elem[0].u.data, msg, 0);
						/* set return code to expr value */
						if (v<0 || (action_flags&ACT_FL_RETURN)
								|| (action_flags&ACT_FL_EXIT) ){
							if (v==EXPR_DROP || (action_flags&ACT_FL_RETURN)
									|| (action_flags&ACT_FL_EXIT) ){
								ret=0;
								return_code = 0;
								break;
							}else{
								LM_WARN("error in expression (l=%d)\n",
										a->line);
							}
						}
					
						ret=1;  /*default is continue */
						if (v>0) {
							if ((a->elem[1].type==ACTIONS_ST)
									&&a->elem[1].u.data){
								ret=run_action_list(
									(struct action*)a->elem[1].u.data,msg );
								/* check if return was done */
								if ((action_flags&ACT_FL_RETURN)
								|| (action_flags&ACT_FL_EXIT) ){
									break;
								}
								return_code = ret;
							} else {
								/* we should not get here */
								return_code = v;
								break;
							}
						} else {
							/* condition was false */
							return_code = v;
							break;
						}
					}
				}
			break;
		case CACHE_STORE_T:
			script_trace("core", "cache_store", msg, a->line) ;
			if ((a->elem[0].type!=STR_ST)) {
				LM_ALERT("BUG in cache_store() - first argument not of"
						" type string [%d]\n",
					a->elem[0].type );
				ret=E_BUG;
				break;
			}

			if ((a->elem[1].type!=STR_ST)) {
				LM_ALERT("BUG in cache_store()  - second argument not of "
						"type string [%d]\n", a->elem[1].type );
				ret=E_BUG;
				break;
			}

			if ((a->elem[2].type!=STR_ST)) {
				LM_ALERT("BUG in cache_store() - third argument not of type"
						" string%d\n", a->elem[2].type );
				ret=E_BUG;
				break;
			}

			str val_s;

			/* parse the name argument */
			pve = (pv_elem_t *)a->elem[1].u.data;
			if ( pv_printf_s(msg, pve, &name_s)!=0 || 
			name_s.len == 0 || name_s.s == NULL) {
				LM_WARN("cannot get string for value\n");
				ret=E_BUG;
				break;
			}

			/* parse the value argument */
			pve = (pv_elem_t *)a->elem[2].u.data;
			if ( pv_printf_s(msg, pve, &val_s)!=0 || 
			val_s.len == 0 || val_s.s == NULL) {
				LM_WARN("cannot get string for value\n");
				ret=E_BUG;
				break;
			}

			/* get the expires value */
			if ( a->elem[3].type == SCRIPTVAR_ST )
			{
				spec = (pv_spec_t*)a->elem[3].u.data;
				memset(&val, 0, sizeof(pv_value_t));
				if(pv_get_spec_value(msg, spec, &val) < 0)
				{
					LM_DBG("Failed to get scriptvar value while executing cache_store\n");
					ret=E_BUG;
					break;
				}
				if (!(val.flags&PV_VAL_INT))
				{
					LM_ERR("Wrong value for cache_store expires, not an integer [%.*s]\n",
							val.rs.len, val.rs.s);
				}
				expires = val.ri;
			}
			else
			if ( a->elem[3].type == NUMBER_ST )
			{
				expires = (int)a->elem[3].u.number;
			}

			ret = cachedb_store( &a->elem[0].u.s, &name_s, &val_s,expires);

			break;
		case CACHE_REMOVE_T:
			script_trace("core", "cache_remove", msg, a->line) ;
			if ((a->elem[0].type!=STR_ST)) {
				LM_ALERT("BUG in cache_remove() %d\n",
					a->elem[0].type );
				ret=E_BUG;
				break;
			}
			if ((a->elem[1].type!=STR_ST)) {
				LM_ALERT("BUG in cache_remove() %d\n",
					a->elem[1].type );
				ret=E_BUG;
				break;
			}
			/* parse the name argument */
			pve = (pv_elem_t *)a->elem[1].u.data;
			if ( pv_printf_s(msg, pve, &name_s)!=0 || 
			name_s.len == 0 || name_s.s == NULL) {
				LM_WARN("cannot get string for value\n");
				ret=E_BUG;
				break;
			}
			ret = cachedb_remove( &a->elem[0].u.s, &name_s);
			break;
		case CACHE_FETCH_T:
			script_trace("core", "cache_fetch", msg, a->line) ;
			if ((a->elem[0].type!=STR_ST)) {
				LM_ALERT("BUG in cache_fetch() %d\n",
					a->elem[0].type );
				ret=E_BUG;
				break;
			}
			if ((a->elem[1].type!=STR_ST)) {
				LM_ALERT("BUG in cache_fetch() %d\n",
					a->elem[1].type );
				ret=E_BUG;
				break;
			}
			if (a->elem[2].type!=SCRIPTVAR_ST){
				LM_ALERT("BUG in cache_fetch() type %d\n",
						a->elem[2].type);
				ret=E_BUG;
				break;
			}
			str aux = {0, 0};
			/* parse the name argument */
			pve = (pv_elem_t *)a->elem[1].u.data;
			if ( pv_printf_s(msg, pve, &name_s)!=0 || 
			name_s.len == 0 || name_s.s == NULL) {
				LM_WARN("cannot get string for value\n");
				ret=E_BUG;
				break;
			}

			ret = cachedb_fetch( &a->elem[0].u.s, &name_s, &aux);
			if(ret > 0)
			{
				val.rs = aux;
				val.flags = PV_VAL_STR;

				spec = (pv_spec_t*)a->elem[2].u.data;
				if (pv_set_value(msg, spec, 0, &val) < 0) {
					LM_ERR("cannot set the variable value\n");
					pkg_free(aux.s);
					return -1;
				}
				pkg_free(aux.s);
			}
			
			break;
		case CACHE_COUNTER_FETCH_T:
			script_trace("core", "cache_counter_fetch", msg, a->line) ;
			if ((a->elem[0].type!=STR_ST)) {
				LM_ALERT("BUG in cache_fetch() %d\n",
					a->elem[0].type );
				ret=E_BUG;
				break;
			}
			if ((a->elem[1].type!=STR_ST)) {
				LM_ALERT("BUG in cache_fetch() %d\n",
					a->elem[1].type );
				ret=E_BUG;
				break;
			}
			if (a->elem[2].type!=SCRIPTVAR_ST){
				LM_ALERT("BUG in cache_fetch() type %d\n",
						a->elem[2].type);
				ret=E_BUG;
				break;
			}
			int aux_counter;
			/* parse the name argument */
			pve = (pv_elem_t *)a->elem[1].u.data;
			if ( pv_printf_s(msg, pve, &name_s)!=0 || 
			name_s.len == 0 || name_s.s == NULL) {
				LM_WARN("cannot get string for value\n");
				ret=E_BUG;
				break;
			}

			ret = cachedb_counter_fetch( &a->elem[0].u.s, &name_s, &aux_counter);
			if(ret > 0)
			{
				val.ri = aux_counter;
				val.flags = PV_TYPE_INT|PV_VAL_INT;

				spec = (pv_spec_t*)a->elem[2].u.data;
				if (pv_set_value(msg, spec, 0, &val) < 0) {
					LM_ERR("cannot set the variable value\n");
					pkg_free(aux.s);
					return -1;
				}
			}
			break;
		case CACHE_ADD_T:
			script_trace("core", "cache_add", msg, a->line) ;
			if ((a->elem[0].type!=STR_ST)) {
				LM_ALERT("BUG in cache_add() - first argument not of"
						" type string [%d]\n",
					a->elem[0].type );
				ret=E_BUG;
				break;
			}

			if ((a->elem[1].type!=STR_ST)) {
				LM_ALERT("BUG in cache_add()  - second argument not of "
						"type string [%d]\n", a->elem[1].type );
				ret=E_BUG;
				break;
			}

			/* parse the name argument */
			pve = (pv_elem_t *)a->elem[1].u.data;
			if ( pv_printf_s(msg, pve, &name_s)!=0 || 
			name_s.len == 0 || name_s.s == NULL) {
				LM_WARN("cannot get string for value\n");
				ret=E_BUG;
				break;
			}

			int increment=0;

			/* get the increment value */
			if ( a->elem[2].type == SCRIPTVAR_ST )
			{
				spec = (pv_spec_t*)a->elem[2].u.data;
				memset(&val, 0, sizeof(pv_value_t));
				if(pv_get_spec_value(msg, spec, &val) < 0)
				{
					LM_DBG("Failed to get scriptvar value while executing cache_add\n");
					ret=E_BUG;
					break;
				}
				if (!(val.flags&PV_VAL_INT))
				{
					LM_ERR("Wrong value for cache_add, not an integer [%.*s]\n",
							val.rs.len, val.rs.s);
				}
				increment = val.ri;
			}
			else if ( a->elem[2].type == NUMBER_ST )
			{
				increment = (int)a->elem[2].u.number;
			}

			expires = (int)a->elem[3].u.number;

			/* TODO - return the new value to script ? */
			ret = cachedb_add(&a->elem[0].u.s, &name_s, increment,expires,NULL);
			break;
		case CACHE_SUB_T:
			script_trace("core", "cache_sub", msg, a->line) ;
			if ((a->elem[0].type!=STR_ST)) {
				LM_ALERT("BUG in cache_sub() - first argument not of"
						" type string [%d]\n",
					a->elem[0].type );
				ret=E_BUG;
				break;
			}

			if ((a->elem[1].type!=STR_ST)) {
				LM_ALERT("BUG in cache_sub()  - second argument not of "
						"type string [%d]\n", a->elem[1].type );
				ret=E_BUG;
				break;
			}

			/* parse the name argument */
			pve = (pv_elem_t *)a->elem[1].u.data;
			if ( pv_printf_s(msg, pve, &name_s)!=0 || 
			name_s.len == 0 || name_s.s == NULL) {
				LM_WARN("cannot get string for value\n");
				ret=E_BUG;
				break;
			}

			int decrement=0;

			/* get the increment value */
			if ( a->elem[2].type == SCRIPTVAR_ST )
			{
				spec = (pv_spec_t*)a->elem[2].u.data;
				memset(&val, 0, sizeof(pv_value_t));
				if(pv_get_spec_value(msg, spec, &val) < 0)
				{
					LM_DBG("Failed to get scriptvar value while executing cache_sub\n");
					ret=E_BUG;
					break;
				}
				if (!(val.flags&PV_VAL_INT))
				{
					LM_ERR("Wrong value for cache_sub, not an integer [%.*s]\n",
							val.rs.len, val.rs.s);
				}
				decrement = val.ri;
			}
			else if ( a->elem[2].type == NUMBER_ST )
			{
				decrement = (int)a->elem[2].u.number;
			}

			expires = (int)a->elem[3].u.number;

			/* TODO - return new value to script ? */
			ret = cachedb_sub(&a->elem[0].u.s, &name_s, decrement,expires,NULL);
			break;
		case CACHE_RAW_QUERY_T:
			if ((a->elem[0].type!=STR_ST)) {
				LM_ALERT("BUG in cache_fetch() %d\n",
					a->elem[0].type );
				ret=E_BUG;
				break;
			}
			if ((a->elem[1].type!=STR_ST)) {
				LM_ALERT("BUG in cache_fetch() %d\n",
					a->elem[1].type );
				ret=E_BUG;
				break;
			}
			if (a->elem[2].u.data != NULL && 
				a->elem[2].type!=STR_ST){
				LM_ALERT("BUG in cache_raw_query() type %d\n",
						a->elem[2].type);
				ret=E_BUG;
				break;
			}
			/* parse the name argument */
			pve = (pv_elem_t *)a->elem[1].u.data;
			if ( pv_printf_s(msg, pve, &name_s)!=0 || 
			name_s.len == 0 || name_s.s == NULL) {
				LM_WARN("cannot get string for value\n");
				ret=E_BUG;
				break;
			}

			cdb_raw_entry **cdb_reply;
			int val_number=0,i,j;
			int key_number=0;
			pvname_list_t *cdb_res,*it;
			int_str avp_val;
			int_str avp_name;
			unsigned short avp_type;

			if (a->elem[2].u.data) {
				cdb_res = (pvname_list_t*)a->elem[2].u.data;
				for (it=cdb_res;it;it=it->next)
					val_number++;

				LM_DBG("The query expects %d results back\n",val_number);

				ret = cachedb_raw_query( &a->elem[0].u.s, &name_s, &cdb_reply,val_number,&key_number);
				if (ret >= 0 && val_number > 0) {
					for (i=key_number-1; i>=0;i--) {
						it=cdb_res;
						for (j=0;j < val_number;j++) {
							avp_type = 0;
							if (pv_get_avp_name(msg,&it->sname.pvp,&avp_name.n,
								&avp_type) != 0) {
								LM_ERR("cannot get avp name [%d/%d]\n",i,j);
								goto next_avp;
							}
							
							switch (cdb_reply[i][j].type) {
								case CDB_INT:
									avp_val.n = cdb_reply[i][j].val.n; 
									break;
								case CDB_STR:
									avp_type |= AVP_VAL_STR;
									avp_val.s = cdb_reply[i][j].val.s;
									break;
								default:
									LM_WARN("Unknown type %d\n",cdb_reply[i][j].type);
									goto next_avp;
							}
							if (add_avp(avp_type,avp_name.n,avp_val) != 0) {
								LM_ERR("Unable to add AVP\n");
								free_raw_fetch(cdb_reply,val_number,key_number);
								return -1;
							}
next_avp:
							if (it) {
								it = it->next;
								if (it==NULL);
									break;
							}
						}
					}
					free_raw_fetch(cdb_reply,val_number,key_number);
				}
			}
			else
				ret = cachedb_raw_query( &a->elem[0].u.s, &name_s, NULL,0,NULL);
			break;
		case XDBG_T:
			script_trace("core", "xdbg", msg, a->line) ;
			if (a->elem[0].type == SCRIPTVAR_ELEM_ST)
			{
				if (xdbg(msg, a->elem[0].u.data, val.rs.s) < 0)
				{
					LM_ALERT("Cannot print message");
					break;
				}
			}
			else
			{
				LM_ALERT("BUG in xdbg() type %d\n", a->elem[0].type);
				ret=E_BUG;
			}
			break;
		case XLOG_T:
			script_trace("core", "xlog", msg, a->line) ;
			if (a->elem[1].u.data != NULL)
			{
				if (a->elem[1].type != SCRIPTVAR_ELEM_ST)
				{
					LM_ALERT("BUG in xlog() type %d\n", a->elem[1].type);
					ret=E_BUG;
					break;
				}
				if (a->elem[0].type != STR_ST)
				{
					LM_ALERT("BUG in xlog() type %d\n", a->elem[0].type);
					ret=E_BUG;
					break;
				}
				if (xlog_2(msg,a->elem[0].u.data, a->elem[1].u.data) < 0)
				{
					LM_ALERT("Cannot print xlog debug message");
					break;
				}
			}
			else
			{
				if (a->elem[0].type != SCRIPTVAR_ELEM_ST)
				{
					LM_ALERT("BUG in xlog() type %d\n", a->elem[0].type);
					ret=E_BUG;
					break;
				}
				if (xlog_1(msg,a->elem[0].u.data, val.rs.s) < 0)
				{
					LM_ALERT("Cannot print xlog debug message");
					break;
				}
			}

			break;
		case RAISE_EVENT_T:
			script_trace("core", "raise_event", msg, a->line) ;
			if (a->elem[0].type != NUMBER_ST) {
				LM_ERR("invalid event id\n");
				ret=E_BUG;
				break;
			}
			if (a->elem[2].u.data) {
				/* three parameters specified */
				ret = evi_raise_script_event(msg, (event_id_t)a->elem[0].u.number,
						a->elem[1].u.data, a->elem[2].u.data);
			} else {
				/* two parameters specified */
				ret = evi_raise_script_event(msg, (event_id_t)a->elem[0].u.number,
						NULL, a->elem[1].u.data);
			}
			if (ret <= 0) {
				LM_ERR("cannot raise event\n");
				ret=E_UNSPEC;
				break;
			}
			break;
		case SUBSCRIBE_EVENT_T:
			script_trace("core", "subscribe_event", msg, a->line) ;
			if (a->elem[0].type != STR_ST || a->elem[1].type != STR_ST) {
				LM_ERR("BUG in subscribe arguments\n");
				ret=E_BUG;
				break;
			}
			if (a->elem[2].u.data) {
				if (a->elem[2].type != NUMBER_ST) {
					LM_ERR("BUG in subscribe expiration time\n");
					ret=E_BUG;
					break;
				} else {
					i = a->elem[2].u.number;
				}
			} else {
				i = 0;
			}

			name_s.s = a->elem[0].u.data;
			name_s.len = strlen(name_s.s);
			/* result should be the socket */
			result.s = a->elem[1].u.data;
			result.len = strlen(result.s);
			ret = evi_event_subscribe(name_s, result, i, 0);
			break;

		case CONSTRUCT_URI_T:
			script_trace("core", "construct_uri", msg, a->line) ;
			for (i=0;i<5;i++)
			{
				pve = (pv_elem_t *)a->elem[i].u.data;
				if (pve->spec.getf)
				{
					if ( pv_printf_s(msg, pve, &vals[i])!=0 || 
						vals[i].len == 0 || vals[i].s == NULL) 
					{
						LM_WARN("cannot get string for value\n");
						ret=E_BUG;
						return -1;
					}
				}
				else
					vals[i] = pve->text;
			}
			
			result.s = construct_uri(&vals[0],&vals[1],&vals[2],&vals[3],&vals[4],
					&result.len);

			if (result.s)
			{
				int_str res;
				int avp_name;
				unsigned short avp_type;

				spec = (pv_spec_t*)a->elem[5].u.data;
				if (pv_get_avp_name( msg, &(spec->pvp), &avp_name,
						&avp_type)!=0){
					LM_CRIT("BUG in getting AVP name\n");
					return -1;
				}

				res.s = result;
				if (add_avp(AVP_VAL_STR|avp_type, avp_name, res)<0){
					LM_ERR("cannot add AVP\n");
					return -1;
				}
			}

			break;
		case GET_TIMESTAMP_T:
			script_trace("core", "get_timestamp", msg, a->line) ;
			if (get_timestamp(&sec,&usec) == 0) {
				int avp_name;
				int_str res;
				unsigned short avp_type;

				spec = (pv_spec_t*)a->elem[0].u.data;
				if (pv_get_avp_name(msg, &(spec->pvp), &avp_name,
						&avp_type) != 0) {
					LM_CRIT("BUG in getting AVP name\n");
					return -1;
				}

				res.n = sec;
				if (add_avp(avp_type, avp_name, res) < 0) {
					LM_ERR("cannot add AVP\n");
					return -1;
				}

				spec = (pv_spec_t*)a->elem[1].u.data;
				if (pv_get_avp_name(msg, &(spec->pvp), &avp_name,
						&avp_type) != 0) {
					LM_CRIT("BUG in getting AVP name\n");
					return -1;
				}

				res.n = usec;
				if (add_avp(avp_type, avp_name, res) < 0) {
					LM_ERR("cannot add AVP\n");
					return -1;
				}
			} else {
				LM_ERR("failed to get time\n");
				return -1;
			}
			break;
		case SWITCH_T:
			script_trace("core", "switch", msg, a->line) ;
			if (a->elem[0].type!=SCRIPTVAR_ST){
				LM_ALERT("BUG in switch() type %d\n",
						a->elem[0].type);
				ret=E_BUG;
				break;
			}
			spec = (pv_spec_t*)a->elem[0].u.data;
			if(pv_get_spec_value(msg, spec, &val)!=0)
			{
				LM_ALERT("BUG - no value in switch()\n");
				ret=E_BUG;
				break;
			}

			/* get the value of pvar */
			if(a->elem[1].type!=ACTIONS_ST) {
				LM_ALERT("BUG in switch() actions\n");
				ret=E_BUG;
				break;
			}
			return_code=1;
			adefault = NULL;
			aitem = (struct action*)a->elem[1].u.data;
			cmatch=0;
			while(aitem)
			{
				if((unsigned char)aitem->type==DEFAULT_T)
					adefault=aitem;
				if(cmatch==0)
				{
					if(aitem->elem[0].type==STR_ST)
					{
						if(val.flags&PV_VAL_STR
								&& val.rs.len==aitem->elem[0].u.s.len
								&& strncasecmp(val.rs.s, aitem->elem[0].u.s.s,
									val.rs.len)==0)
							cmatch = 1;
					} else { /* number */
						if(val.flags&PV_VAL_INT && 
								val.ri==aitem->elem[0].u.number)
							cmatch = 1;
					}
				}
				if(cmatch==1)
				{
					if(aitem->elem[1].u.data)
					{
						return_code=run_action_list(
							(struct action*)aitem->elem[1].u.data, msg);
						if ((action_flags&ACT_FL_RETURN) ||
						(action_flags&ACT_FL_EXIT))
							break;
					}
					if(aitem->elem[2].u.number==1)
						break;
				}
				aitem = aitem->next;
			}
			if((cmatch==0) && (adefault!=NULL))
			{
				LM_DBG("switch: running default statement\n");
				if(adefault->elem[0].u.data)
					return_code=run_action_list(
						(struct action*)adefault->elem[0].u.data, msg);
			}
			ret=return_code;
			break;
		case MODULE_T:
			script_trace("module", ((cmd_export_t*)(a->elem[0].u.data))->name,
				msg, a->line) ;
			if ( (a->elem[0].type==CMD_ST) && a->elem[0].u.data ) {
				ret=((cmd_export_t*)(a->elem[0].u.data))->function(msg,
						 (char*)a->elem[1].u.data, (char*)a->elem[2].u.data,
						 (char*)a->elem[3].u.data, (char*)a->elem[4].u.data,
						 (char*)a->elem[5].u.data, (char*)a->elem[6].u.data);
			}else{
				LM_ALERT("BUG in module call\n");
			}
			break;
		case FORCE_RPORT_T:
			script_trace("core", "force_rport", msg, a->line) ;
			msg->msg_flags|=FL_FORCE_RPORT;
			ret=1; /* continue processing */
			break;
		case FORCE_LOCAL_RPORT_T:
			script_trace("core", "force_local_rport", msg, a->line) ;
			msg->msg_flags|=FL_FORCE_LOCAL_RPORT;
			ret=1; /* continue processing */
			break;
		case SET_ADV_ADDR_T:
			script_trace("core", "set_adv_addr", msg, a->line) ;
			if (a->elem[0].type!=STR_ST){
				LM_ALERT("BUG in set_advertised_address() "
						"type %d\n", a->elem[0].type);
				ret=E_BUG;
				break;
			}
			str adv_addr;
			pve = (pv_elem_t *)a->elem[0].u.data;
			if ( pv_printf_s(msg, pve, &adv_addr)!=0 || 
			adv_addr.len == 0 || adv_addr.s == NULL) {
				LM_WARN("cannot get string for value\n");
				ret=E_BUG;
				break;
			}
			LM_DBG("adv address = [%.*s]\n",adv_addr.len,adv_addr.s);
			msg->set_global_address=adv_addr;
			ret=1; /* continue processing */
			break;
		case SET_ADV_PORT_T:
			script_trace("core", "set_adv_port", msg, a->line) ;
			if (a->elem[0].type!=STR_ST){
				LM_ALERT("BUG in set_advertised_port() "
						"type %d\n", a->elem[0].type);
				ret=E_BUG;
				break;
			}

			msg->set_global_port=*((str*)a->elem[0].u.data);
			ret=1; /* continue processing */
			break;
#ifdef USE_TCP
		case FORCE_TCP_ALIAS_T:
			script_trace("core", "force_tcp_alias", msg, a->line) ;
			if ( msg->rcv.proto==PROTO_TCP
#ifdef USE_TLS
					|| msg->rcv.proto==PROTO_TLS
#endif
			   ){
				
				if (a->elem[0].type==NOSUBTYPE)	port=msg->via1->port;
				else if (a->elem[0].type==NUMBER_ST)
					port=(int)a->elem[0].u.number;
				else{
					LM_ALERT("BUG in force_tcp_alias"
							" port type %d\n", a->elem[0].type);
					ret=E_BUG;
					break;
				}
						
				if (tcpconn_add_alias(msg->rcv.proto_reserved1, port,
									msg->rcv.proto)!=0){
					LM_ERR("tcp alias failed\n");
					ret=E_UNSPEC;
					break;
				}
			}
#endif
			ret=1; /* continue processing */
			break;
		case FORCE_SEND_SOCKET_T:
			script_trace("core", "force_send_socket", msg, a->line) ;
			if (a->elem[0].type!=SOCKETINFO_ST){
				LM_ALERT("BUG in force_send_socket argument"
						" type: %d\n", a->elem[0].type);
				ret=E_BUG;
				break;
			}
			msg->force_send_socket=(struct socket_info*)a->elem[0].u.data;
			ret=1; /* continue processing */
			break;
		case SERIALIZE_BRANCHES_T:
			script_trace("core", "serialize_branches", msg, a->line) ;
			if (a->elem[0].type!=NUMBER_ST){
				LM_ALERT("BUG in serialize_branches argument"
						" type: %d\n", a->elem[0].type);
				ret=E_BUG;
				break;
			}
			if (serialize_branches(msg,(int)a->elem[0].u.number)!=0) {
				LM_ERR("serialize_branches failed\n");
				ret=E_UNSPEC;
				break;
			}
			ret=1; /* continue processing */
			break;
		case NEXT_BRANCHES_T:
			script_trace("core", "next_branches", msg, a->line) ;
			if ((ret=next_branches(msg))<0) {
				LM_ERR("next_branches failed\n");
				ret=E_UNSPEC;
				break;
			}
			/* continue processing */
			break;
		case EQ_T:
		case COLONEQ_T:
		case PLUSEQ_T:
		case MINUSEQ_T:
		case DIVEQ_T:
		case MULTEQ_T:
		case MODULOEQ_T:
		case BANDEQ_T:
		case BOREQ_T:
		case BXOREQ_T:
			ret = do_assign(msg, a);
			break;
		case USE_BLACKLIST_T:
			script_trace("core", "use_blacklist", msg, a->line) ;
			mark_for_search((struct bl_head*)a->elem[0].u.data, 1);
			break;
		case UNUSE_BLACKLIST_T:
			script_trace("core", "unuse_blacklist", msg, a->line);
			mark_for_search((struct bl_head*)a->elem[0].u.data, 0);
			break;
		case PV_PRINTF_T:
			script_trace("core", "pv_printf", msg, a->line);
			ret = -1;
			spec = (pv_spec_p)a->elem[0].u.data;
			if(!pv_is_w(spec))
			{
				LM_ERR("read only PV in first parameter of pv_printf\n");
				goto error;
			}

			model = (pv_elem_p)a->elem[1].u.data;

			memset(&val, 0, sizeof(pv_value_t));
			if(pv_printf_s(msg, model, &val.rs)!=0)
			{
				LM_ERR("cannot eval second parameter\n");
				goto error;
			}
			val.flags = PV_VAL_STR;
			if(pv_set_value(msg, spec, EQ_T, &val)<0)
			{
				LM_ERR("setting PV failed\n");
				goto error;
			}
			
			ret = 1;
			break;
		case SCRIPT_TRACE_T:
			script_trace("core", "script_trace", msg, a->line);
			if (a->elem[0].type==NOSUBTYPE) {
				use_script_trace = 0;
			} else {
				
				use_script_trace = 1;
				
				if (a->elem[0].type != NUMBER_ST ||
					a->elem[1].type != SCRIPTVAR_ELEM_ST) {

					LM_ERR("BUG in use_script_trace() arguments\n");
					ret=E_BUG;
					break;
				}

				if (a->elem[2].type!=NOSUBTYPE) {
					script_trace_info = (char *)a->elem[2].u.data;
				} else {
					script_trace_info = NULL;
				}

				script_trace_log_level = (int)a->elem[0].u.number;
				script_trace_elem = *(pv_elem_p)a->elem[1].u.data;
			}

			break;
		default:
			LM_ALERT("BUG - unknown type %d\n", a->type);
			goto error;
	}

	if((unsigned char)a->type!=IF_T && (unsigned char)a->type!=ROUTE_T)
		return_code = ret;
/*skip:*/

	update_longest_action();
	return ret;

error:
	LM_ERR("error at line: %d\n", a->line);
	update_longest_action();
	return ret;
	
error_uri:
	LM_ERR("set*: uri too long\n");
	if (new_uri) pkg_free(new_uri);
	update_longest_action();
	return E_UNSPEC;
error_fwd_uri:
	update_longest_action();
	return ret;
}
Пример #26
0
/*! \brief 
 * \return 0/1 (false/true) or -1 on error, -127 EXPR_DROP 
 */
static int eval_elem(struct expr* e, struct sip_msg* msg, pv_value_t *val)
{

	struct sip_uri uri;
	int ret;
	int retl;
	int retr;
	int ival;
	pv_value_t lval;
	pv_value_t rval;
	char *p;
	int i,n;
	
	ret=E_BUG;
	if (e->type!=ELEM_T){
		LM_CRIT("invalid type\n");
		goto error;
	}
	
	if(val) memset(val, 0, sizeof(pv_value_t));

	switch(e->left.type){
		case METHOD_O:
				ret=comp_strval(msg, e->op, &msg->first_line.u.request.method,
						&e->right);
				break;
		case URI_O:
				if(msg->new_uri.s){
					if (e->right.type==MYSELF_ST){
						if (parse_sip_msg_uri(msg)<0) ret=-1;
						else	ret=check_self_op(e->op, &msg->parsed_uri.host,
									msg->parsed_uri.port_no?
									msg->parsed_uri.port_no:SIP_PORT);
					}else{
						ret=comp_strval(msg, e->op, &msg->new_uri, &e->right);
					}
				}else{
					if (e->right.type==MYSELF_ST){
						if (parse_sip_msg_uri(msg)<0) ret=-1;
						else	ret=check_self_op(e->op, &msg->parsed_uri.host,
									msg->parsed_uri.port_no?
									msg->parsed_uri.port_no:SIP_PORT);
					}else{
						ret=comp_strval(msg, e->op,
								&msg->first_line.u.request.uri,
								&e->right);
					}
				}
				break;
		case FROM_URI_O:
				if (parse_from_header(msg)<0){
					LM_ERR("bad or missing From: header\n");
					goto error;
				}
				if (e->right.type==MYSELF_ST){
					if (parse_uri(get_from(msg)->uri.s, get_from(msg)->uri.len,
									&uri) < 0){
						LM_ERR("bad uri in From:\n");
						goto error;
					}
					ret=check_self_op(e->op, &uri.host,
										uri.port_no?uri.port_no:SIP_PORT);
				}else{
					ret=comp_strval(msg, e->op, &get_from(msg)->uri,
							&e->right);
				}
				break;
		case TO_URI_O:
				if ((msg->to==0) && ((parse_headers(msg, HDR_TO_F, 0)==-1) ||
							(msg->to==0))){
					LM_ERR("bad or missing To: header\n");
					goto error;
				}
				/* to content is parsed automatically */
				if (e->right.type==MYSELF_ST){
					if (parse_uri(get_to(msg)->uri.s, get_to(msg)->uri.len,
									&uri) < 0){
						LM_ERR("bad uri in To:\n");
						goto error;
					}
					ret=check_self_op(e->op, &uri.host,
										uri.port_no?uri.port_no:SIP_PORT);
				}else{
					ret=comp_strval(msg, e->op, &get_to(msg)->uri,
										&e->right);
				}
				break;
		case SRCIP_O:
				ret=comp_ip(msg, e->op, &msg->rcv.src_ip, &e->right);
				break;
		case DSTIP_O:
				ret=comp_ip(msg, e->op, &msg->rcv.dst_ip, &e->right);
				break;
		case NUMBER_O:
				ret=!(!e->right.v.n); /* !! to transform it in {0,1} */
				break;
		case ACTION_O:
				ret=run_action_list( (struct action*)e->right.v.data, msg);
				if(val)
				{
					val->flags = PV_TYPE_INT|PV_VAL_INT;
					val->ri = ret;
				}
				if (ret<=0) ret=(ret==0)?EXPR_DROP:0;
				else ret=1;
				return ret;
		case EXPR_O:
				retl = retr = 0;
				memset(&lval, 0, sizeof(pv_value_t));
				memset(&rval, 0, sizeof(pv_value_t));
				if(e->left.v.data)
					retl=eval_expr((struct expr*)e->left.v.data,msg,&lval);
				if(lval.flags == PV_VAL_NONE)
				{
					pv_value_destroy(&lval);
					pv_value_destroy(&rval);
					return 0;
				}
				if(e->op == BNOT_OP)
				{
					if(lval.flags&PV_VAL_INT)
					{
						if(val!=NULL)
						{
							val->flags = PV_TYPE_INT|PV_VAL_INT;
							val->ri = ~lval.ri;
						}
						pv_value_destroy(&lval);
						pv_value_destroy(&rval);
						return (val->ri)?1:0;
					}
					LM_ERR("binary NOT on non-numeric value\n");
					pv_value_destroy(&lval);
					pv_value_destroy(&rval);
					return 0;
				}
				if(e->right.v.data)
					retr=eval_expr((struct expr*)e->right.v.data,msg,&rval);
			
				if(lval.flags&PV_TYPE_INT)
				{
					if( (rval.flags&PV_VAL_NULL) )
					{
						rval.ri = 0;
					} else if(!(rval.flags&PV_VAL_INT))
					{
						LM_ERR("invalid numeric operands\n");
						pv_value_destroy(&lval);
						pv_value_destroy(&rval);
						return 0;
					}
					if(val!=NULL)
						val->flags = PV_TYPE_INT|PV_VAL_INT;

					ival = 0;
					switch(e->op) {
						case PLUS_OP:
							ival = lval.ri + rval.ri;
							break;
						case MINUS_OP:
							ival = lval.ri - rval.ri;
							break;
						case DIV_OP:
							if(rval.ri==0)
							{
								LM_ERR("divide by 0\n");
								pv_value_destroy(&lval);
								pv_value_destroy(&rval);
								return 0;
							} else 
								ival = lval.ri / rval.ri;
							break;
						case MULT_OP:
							ival = lval.ri * rval.ri;
							break;
						case MODULO_OP:
							if(rval.ri==0)
							{
								LM_ERR("divide by 0\n");
								pv_value_destroy(&lval);
								pv_value_destroy(&rval);
								return 0;
							} else 
								ival = lval.ri % rval.ri;
							break;
						case BAND_OP:
							ival = lval.ri & rval.ri;
							break;
						case BOR_OP:
							ival = lval.ri | rval.ri;
							break;
						case BXOR_OP:
							ival = lval.ri ^ rval.ri;
							break;
						case BLSHIFT_OP:
							ival = lval.ri << rval.ri;
							break;
						case BRSHIFT_OP:
							ival = lval.ri >> rval.ri;
							break;
						default:
							LM_ERR("invalid int op %d\n", e->op);
								val->ri = 0;
							pv_value_destroy(&lval);
							pv_value_destroy(&rval);
							return 0;
					}
					pv_value_destroy(&lval);
					pv_value_destroy(&rval);
					if(val!=NULL) val->ri = ival;
					return (ival)?1:0;
				} else if (e->op == PLUS_OP) {
					if( (rval.flags&PV_VAL_NULL) || (val==NULL)) {
						if (val) val->flags|=PV_VAL_STR;
						ret = (lval.rs.len>0 || rval.rs.len>0);
						pv_value_destroy(&lval);
						pv_value_destroy(&rval);
						return ret;
					}
					if(!(rval.flags&PV_VAL_STR))
					{
						LM_ERR("invalid string operands\n");
						pv_value_destroy(&lval);
						pv_value_destroy(&rval);
						return 0;
					}
					val->rs.s=(char*)pkg_malloc((lval.rs.len+rval.rs.len+1)
							*sizeof(char));
					if(val->rs.s==0)
					{
						LM_ERR("no more memory\n");
						pv_value_destroy(&lval);
						pv_value_destroy(&rval);
						return 0;
					}
					val->flags = PV_VAL_PKG|PV_VAL_STR;
					memcpy(val->rs.s, lval.rs.s, lval.rs.len);
					memcpy(val->rs.s+lval.rs.len, rval.rs.s, rval.rs.len);
					val->rs.len = lval.rs.len + rval.rs.len;
					val->rs.s[val->rs.len] = '\0';
					pv_value_destroy(&lval);
					pv_value_destroy(&rval);
					return 1;
				} else if ((lval.flags & PV_VAL_STR) && (rval.flags & PV_VAL_STR)) {
					if (lval.rs.len != rval.rs.len)
					{
						LM_ERR("Different length string operands\n");
						pv_value_destroy(&lval);
						pv_value_destroy(&rval);
						return 0;
					}
					n = lval.rs.len;
					val->rs.s = pkg_malloc(n+1);
					if (!val->rs.s)
					{
						LM_ERR("no more memory\n");
						pv_value_destroy(&lval);
						pv_value_destroy(&rval);
						return 0;
					}
					switch(e->op) {
						case BAND_OP:
							for (i=0;i<n;i++)
								val->rs.s[i] = lval.rs.s[i] & rval.rs.s[i];
							break;
						case BOR_OP:
							for (i=0;i<n;i++)
								val->rs.s[i] = lval.rs.s[i] | rval.rs.s[i];
							break;
						case BXOR_OP:
							for (i=0;i<n;i++)
								val->rs.s[i] = lval.rs.s[i] ^ rval.rs.s[i];
							break;
						default:
							LM_ERR("Only bitwise operations can be applied on strings\n");
							val->ri = 0;
							pv_value_destroy(&lval);
							pv_value_destroy(&rval);
							return 0;
					}
					val->flags = PV_VAL_PKG|PV_VAL_STR;
					val->rs.len = n;
					val->rs.s[n] = '\0';
					pv_value_destroy(&lval);
					pv_value_destroy(&rval);
					return 1;
				}
				else {
					LM_ERR("Invalid operator : %d \n",e->op);
					pv_value_destroy(&lval);
					pv_value_destroy(&rval);
					return 0;
				}
				break;
		case SRCPORT_O:
				ret=comp_no(msg->rcv.src_port, 
					e->right.v.data, /* e.g., 5060 */
					e->op, /* e.g. == */
					e->right.type /* 5060 is number */);
				break;
		case DSTPORT_O:
				ret=comp_no(msg->rcv.dst_port, e->right.v.data, e->op, 
							e->right.type);
				break;
		case PROTO_O:
				ret=comp_no(msg->rcv.proto, e->right.v.data, e->op,
						e->right.type);
				break;
		case AF_O:
				ret=comp_no(msg->rcv.src_ip.af, e->right.v.data, e->op,
						e->right.type);
				break;
		case RETCODE_O:
				ret=comp_no(return_code, e->right.v.data, e->op,
						e->right.type);
				break;
		case MSGLEN_O:
				ret=comp_no(msg->len, e->right.v.data, e->op,
						e->right.type);
				break;
		case STRINGV_O:
				if(val) {
					val->flags = PV_VAL_STR;
					val->rs = e->left.v.s;
				}
				/* optimization for no dup ?!?! */
				return (e->left.v.s.len>0)?1:0;
		case NUMBERV_O:
				if(val) {
					val->flags = PV_TYPE_INT|PV_VAL_INT;
					val->ri = e->left.v.n;
				}
				ret=!(!e->left.v.n); /* !! to transform it in {0,1} */
				return ret;
		case SCRIPTVAR_O:
				if(e->op==NO_OP)
				{
					memset(&rval, 0, sizeof(pv_value_t));
					if(pv_get_spec_value(msg, e->right.v.spec, &rval)==0)
					{
						if(rval.flags==PV_VAL_NONE || (rval.flags&PV_VAL_NULL)
								|| (rval.flags&PV_VAL_EMPTY)
								|| ((rval.flags&PV_TYPE_INT)&&rval.ri==0))
						{
							pv_value_destroy(&rval);
							return 0;
						}
						if(rval.flags&PV_TYPE_INT)
						{
							pv_value_destroy(&rval);
							return 1;
						}
						if(rval.rs.len!=0)
						{
							pv_value_destroy(&rval);
							return 1;
						}
						pv_value_destroy(&rval);
					}
					return 0;
				}
				if(e->op==VALUE_OP)
				{
					if(pv_get_spec_value(msg, e->left.v.spec, &lval)==0)
					{
						if(val!=NULL)
							memcpy(val, &lval, sizeof(pv_value_t));
						if(lval.flags&PV_VAL_STR)
						{
							if(!((lval.flags&PV_VAL_PKG) 
									|| (lval.flags&PV_VAL_SHM)))
							{
								if(val!=NULL)
								{
									/* do pkg duplicate */
									p = (char*)pkg_malloc((val->rs.len+1)
											*sizeof(char));
									if(p==0)
									{
										LM_ERR("no more pkg memory\n");
										memset(val, 0, sizeof(pv_value_t));
										return 0;
									}
									memcpy(p, val->rs.s, val->rs.len);
									p[val->rs.len] = 0;
									val->rs.s = p;
									val->flags|= PV_VAL_PKG;
								}
							}
							return 1;
						}
						if(lval.flags==PV_VAL_NONE 
								|| (lval.flags & PV_VAL_NULL)
								|| (lval.flags & PV_VAL_EMPTY))
							return 0;
						if(lval.flags&PV_TYPE_INT)
							return (lval.ri!=0);
						else
							return (lval.rs.len>0);
					}
					return 0;
				}

				ret=comp_scriptvar(msg, e->op, &e->left, &e->right);
				break;
		default:
				LM_CRIT("invalid operand %d\n", e->left.type);
	}
Пример #27
0
void do_if (int sharp)
{
   char c;
   char d;

#ifdef DEBUG_IF

   if (debugging)
   {
      outputc('<');
      outputc(sharp ? '#' : '@');
      outputs("if: ");
      // fflush(outfile);
   }
#endif
   if (in_false_if())
   {
      n_skipped_ifs ++;
#ifdef DEBUG_IF

      if (debugging)
      {
         outputs("in-false, skipped>");
         // fflush(outfile);
      }
#endif
      if (sharp)
      {
         d = '\0';
         do
         {
            c = d;
            d = Get();
         }
         while ((c == '\\') || (d != '\n'));
      }
      return ;
   }
   if (! sharp)
   {
      c = getnonspace();
      if (c != '(')
      {
         err_head();
         fprintf(stderr, "@if must have ()s\n");
         Push(c);
         iffalse();
#ifdef DEBUG_IF

         if (debugging)
         {
            outputc('>');
            // fflush(outfile);
         }
#endif
         return ;
      }
   }
   if (eval_expr(sharp, 0))
   {
      iftrue();
   }
   else
   {
      iffalse();
   }
#ifdef DEBUG_IF
   if (debugging)
   {
      outputc('>');
      // fflush(outfile);
   }
#endif
}
Пример #28
0
/* print the value of stat variable STAT */
void
stat_print_stat(struct stat_sdb_t *sdb,	/* stat database */
		struct stat_stat_t *stat,/* stat variable */
		FILE *fd)		/* output stream */
{
  struct eval_value_t val;

  switch (stat->sc)
    {
    case sc_int:
      fprintf(fd, "%-22s ", stat->name);
      myfprintf(fd, stat->format, *stat->variant.for_int.var);
      fprintf(fd, " # %s", stat->desc);
      break;
    case sc_uint:
      fprintf(fd, "%-22s ", stat->name);
      myfprintf(fd, stat->format, *stat->variant.for_uint.var);
      fprintf(fd, " # %s", stat->desc);
      break;
#ifdef HOST_HAS_QWORD
    case sc_qword:
      {
	char buf[128];

	fprintf(fd, "%-22s ", stat->name);
	mysprintf(buf, stat->format, *stat->variant.for_qword.var);
	fprintf(fd, "%s # %s", buf, stat->desc);
      }
      break;
    case sc_sqword:
      {
	char buf[128];

	fprintf(fd, "%-22s ", stat->name);
	mysprintf(buf, stat->format, *stat->variant.for_sqword.var);
	fprintf(fd, "%s # %s", buf, stat->desc);
      }
      break;
#endif /* HOST_HAS_QWORD */
    case sc_float:
      fprintf(fd, "%-22s ", stat->name);
      myfprintf(fd, stat->format, (double)*stat->variant.for_float.var);
      fprintf(fd, " # %s", stat->desc);
      break;
    case sc_double:
      fprintf(fd, "%-22s ", stat->name);
      myfprintf(fd, stat->format, *stat->variant.for_double.var);
      fprintf(fd, " # %s", stat->desc);
      break;
    case sc_dist:
      print_dist(stat, fd);
      break;
    case sc_sdist:
      print_sdist(stat, fd);
      break;
    case sc_formula:
      {
	/* instantiate a new evaluator to avoid recursion problems */
	struct eval_state_t *es = eval_new(stat_eval_ident, sdb);
	char *endp;

	fprintf(fd, "%-22s ", stat->name);
	val = eval_expr(es, stat->variant.for_formula.formula, &endp);
	if (eval_error != ERR_NOERR || *endp != '\0')
	  fprintf(fd, "<error: %s>", eval_err_str[eval_error]);
	else
	  myfprintf(fd, stat->format, eval_as_double(val));
	fprintf(fd, " # %s", stat->desc);

	/* done with the evaluator */
	eval_delete(es);
      }
      break;
    default:
      panic("bogus stat class");
    }
  fprintf(fd, "\n");
}
Пример #29
0
static struct block *postfix_expression(struct block *block)
{
    struct var root;

    block = primary_expression(block);
    root = block->expr;

    while (1) {
        const struct member *field;
        const struct typetree *type;
        struct var expr, copy, *arg;
        struct token tok;
        int i, j;

        switch ((tok = peek()).token) {
        case '[':
            do {
                /* Evaluate a[b] = *(a + b). The semantics of pointer arithmetic
                 * takes care of multiplying b with the correct width. */
                consume('[');
                block = expression(block);
                root = eval_expr(block, IR_OP_ADD, root, block->expr);
                root = eval_deref(block, root);
                consume(']');
            } while (peek().token == '[');
            break;
        case '(':
            type = root.type;
            if (is_pointer(root.type) && is_function(root.type->next))
                type = type_deref(root.type);
            else if (!is_function(root.type)) {
                error("Expression must have type pointer to function, was %t.",
                    root.type);
                exit(1);
            }
            consume('(');
            arg = calloc(nmembers(type), sizeof(*arg));
            for (i = 0; i < nmembers(type); ++i) {
                if (peek().token == ')') {
                    error("Too few arguments, expected %d but got %d.",
                        nmembers(type), i);
                    exit(1);
                }
                block = assignment_expression(block);
                arg[i] = block->expr;
                /* todo: type check here. */
                if (i < nmembers(type) - 1) {
                    consume(',');
                }
            }
            while (is_vararg(type) && peek().token != ')') {
                consume(',');
                arg = realloc(arg, (i + 1) * sizeof(*arg));
                block = assignment_expression(block);
                arg[i] = block->expr;
                i++;
            }
            consume(')');
            for (j = 0; j < i; ++j)
                param(block, arg[j]);
            free(arg);
            root = eval_call(block, root);
            break;
        case '.':
            consume('.');
            tok = consume(IDENTIFIER);
            field = find_type_member(root.type, tok.strval);
            if (!field) {
                error("Invalid field access, no member named '%s'.",
                    tok.strval);
                exit(1);
            }
            root.type = field->type;
            root.offset += field->offset;
            break;
        case ARROW:
            consume(ARROW);
            tok = consume(IDENTIFIER);
            if (is_pointer(root.type) && is_struct_or_union(root.type->next)) {
                field = find_type_member(type_deref(root.type), tok.strval);
                if (!field) {
                    error("Invalid field access, no member named '%s'.",
                        tok.strval);
                    exit(1);
                }

                /* Make it look like a pointer to the field type, then perform
                 * normal dereferencing. */
                root.type = type_init(T_POINTER, field->type);
                root = eval_deref(block, root);
                root.offset = field->offset;
            } else {
                error("Invalid field access.");
                exit(1);
            }
            break;
        case INCREMENT:
            consume(INCREMENT);
            copy = create_var(root.type);
            eval_assign(block, copy, root);
            expr = eval_expr(block, IR_OP_ADD, root, var_int(1));
            eval_assign(block, root, expr);
            root = copy;
            break;
        case DECREMENT:
            consume(DECREMENT);
            copy = create_var(root.type);
            eval_assign(block, copy, root);
            expr = eval_expr(block, IR_OP_SUB, root, var_int(1));
            eval_assign(block, root, expr);
            root = copy;
            break;
        default:
            block->expr = root;
            return block;
        }
    }
}
Пример #30
0
static struct block *unary_expression(struct block *block)
{
    struct var value;

    switch (peek().token) {
    case '&':
        consume('&');
        block = cast_expression(block);
        block->expr = eval_addr(block, block->expr);
        break;
    case '*':
        consume('*');
        block = cast_expression(block);
        block->expr = eval_deref(block, block->expr);
        break;
    case '!':
        consume('!');
        block = cast_expression(block);
        block->expr = eval_expr(block, IR_OP_EQ, var_int(0), block->expr);
        break;
    case '~':
        consume('~');
        block = cast_expression(block);
        block->expr = eval_expr(block, IR_NOT, block->expr);
        break;
    case '+':
        consume('+');
        block = cast_expression(block);
        block->expr.lvalue = 0;
        break;
    case '-':
        consume('-');
        block = cast_expression(block);
        block->expr = eval_expr(block, IR_OP_SUB, var_int(0), block->expr);
        break;
    case SIZEOF: {
        struct typetree *type;
        struct block *head = cfg_block_init(), *tail;
        consume(SIZEOF);
        if (peek().token == '(') {
            switch (peekn(2).token) {
            case FIRST(type_name):
                consume('(');
                type = declaration_specifiers(NULL);
                if (peek().token != ')') {
                    type = declarator(type, NULL);
                }
                consume(')');
                break;
            default:
                tail = unary_expression(head);
                type = (struct typetree *) tail->expr.type;
                break;
            }
        } else {
            tail = unary_expression(head);
            type = (struct typetree *) tail->expr.type;
        }
        if (is_function(type)) {
            error("Cannot apply 'sizeof' to function type.");
        }
        if (!size_of(type)) {
            error("Cannot apply 'sizeof' to incomplete type.");
        }
        block->expr = var_int(size_of(type));
        break;
    }
    case INCREMENT:
        consume(INCREMENT);
        block = unary_expression(block);
        value = block->expr;
        block->expr = eval_expr(block, IR_OP_ADD, value, var_int(1));
        block->expr = eval_assign(block, value, block->expr);
        break;
    case DECREMENT:
        consume(DECREMENT);
        block = unary_expression(block);
        value = block->expr;
        block->expr = eval_expr(block, IR_OP_SUB, value, var_int(1));
        block->expr = eval_assign(block, value, block->expr);
        break;
    default:
        block = postfix_expression(block);
        break;
    }

    return block;
}