#include "smatch.h"
#include "smatch_extra.h"
DECLARE_ALLOCATOR(sname);
__ALLOCATOR(struct expression, "temporary expr", tmp_expression);
static struct position get_cur_pos(void)
{
static struct position pos;
static struct position none;
struct expression *expr;
struct statement *stmt;
expr = last_ptr_list((struct ptr_list *)big_expression_stack);
stmt = last_ptr_list((struct ptr_list *)big_statement_stack);
if (expr)
pos = expr->pos;
else if (stmt)
pos = stmt->pos;
else
pos = none;
return pos;
}
struct expression *alloc_tmp_expression(struct position pos, int type)
{
struct expression *expr;
expr = __alloc_tmp_expression(0);
expr->smatch_flags |= Tmp;
expr->type = type;
expr->pos = pos;
return expr;
}
void free_tmp_expressions(void)
{
clear_tmp_expression_alloc();
}
struct expression *zero_expr(void)
{
struct expression *zero;
zero = alloc_tmp_expression(get_cur_pos(), EXPR_VALUE);
zero->value = 0;
zero->ctype = &int_ctype;
return zero;
}
struct expression *value_expr(long long val)
{
struct expression *expr;
if (!val)
return zero_expr();
expr = alloc_tmp_expression(get_cur_pos(), EXPR_VALUE);
expr->value = val;
expr->ctype = &llong_ctype;
return expr;
}
struct expression *member_expression(struct expression *deref, int op, struct ident *member)
{
struct expression *expr;
expr = alloc_tmp_expression(deref->pos, EXPR_DEREF);
expr->op = op;
expr->deref = deref;
expr->member = member;
expr->member_offset = -1;
return expr;
}
struct expression *preop_expression(struct expression *expr, int op)
{
struct expression *preop;
preop = alloc_tmp_expression(expr->pos, EXPR_PREOP);
preop->unop = expr;
preop->op = op;
return preop;
}
struct expression *deref_expression(struct expression *expr)
{
if (expr->type == EXPR_BINOP)
expr = preop_expression(expr, '(');
return preop_expression(expr, '*');
}
struct expression *assign_expression(struct expression *left, int op, struct expression *right)
{
struct expression *expr;
if (!right)
return NULL;
expr = alloc_expression(right->pos, EXPR_ASSIGNMENT);
expr->op = op;
expr->left = left;
expr->right = right;
return expr;
}
struct expression *binop_expression(struct expression *left, int op, struct expression *right)
{
struct expression *expr;
expr = alloc_tmp_expression(right->pos, EXPR_BINOP);
expr->op = op;
expr->left = left;
expr->right = right;
return expr;
}
struct expression *array_element_expression(struct expression *array, struct expression *offset)
{
struct expression *expr;
expr = binop_expression(array, '+', offset);
return deref_expression(expr);
}
struct expression *symbol_expression(struct symbol *sym)
{
struct expression *expr;
expr = alloc_tmp_expression(sym->pos, EXPR_SYMBOL);
expr->symbol = sym;
expr->symbol_name = sym->ident;
return expr;
}
struct expression *compare_expression(struct expression *left, int op, struct expression *right)
{
struct expression *expr;
expr = alloc_tmp_expression(get_cur_pos(), EXPR_COMPARE);
expr->op = op;
expr->left = left;
expr->right = right;
return expr;
}
struct expression *string_expression(char *str)
{
struct expression *ret;
struct string *string;
int len;
len = strlen(str) + 1;
string = (void *)__alloc_sname(4 + len);
string->length = len;
string->immutable = 0;
memcpy(string->data, str, len);
ret = alloc_tmp_expression(get_cur_pos(), EXPR_STRING);
ret->wide = 0;
ret->string = string;
return ret;
}
struct expression *call_expression(struct expression *fn, struct expression_list *args)
{
struct expression *expr;
expr = alloc_tmp_expression(fn->pos, EXPR_CALL);
expr->fn = fn;
expr->args = args;
return expr;
}
static struct expression *get_expression_from_base_and_str(struct expression *base, const char *addition)
{
struct expression *ret = NULL;
struct token *token, *prev, *end;
char *alloc;
if (addition[0] == '\0')
return base;
alloc = alloc_string_newline(addition);
token = tokenize_buffer(alloc, strlen(alloc), &end);
if (!token)
goto free;
if (token_type(token) != TOKEN_STREAMBEGIN)
goto free;
token = token->next;
ret = base;
while (token_type(token) == TOKEN_SPECIAL &&
(token->special == SPECIAL_DEREFERENCE || token->special == '.')) {
prev = token;
token = token->next;
if (token_type(token) != TOKEN_IDENT)
goto free;
switch (prev->special) {
case SPECIAL_DEREFERENCE:
ret = deref_expression(ret);
ret = member_expression(ret, '*', token->ident);
break;
case '.':
ret = member_expression(ret, '.', token->ident);
break;
default:
goto free;
}
token = token->next;
}
if (token_type(token) != TOKEN_STREAMEND)
goto free;
free:
free_string(alloc);
return ret;
}
struct expression *gen_expression_from_name_sym(const char *name, struct symbol *sym)
{
struct expression *base;
int skip = 0;
struct expression *ret;
if (!name || !sym)
return NULL;
base = symbol_expression(sym);
while (name[skip] != '\0' && name[skip] != '.' && name[skip] != '-')
skip++;
ret = get_expression_from_base_and_str(base, name + skip);
if (ret) {
char *new = expr_to_str(ret);
if (!new || strcmp(name, new) != 0)
return NULL;
}
return ret;
}
struct expression *gen_expression_from_key(struct expression *arg, const char *key)
{
struct expression *ret;
struct token *token, *prev, *end;
const char *p = key;
char buf[4095];
char *alloc;
size_t len;
if (key[0] != '$')
return NULL;
p++;
while (*p >= '0' && *p <= '9')
p++;
len = snprintf(buf, sizeof(buf), "%s\n", p);
alloc = alloc_string(buf);
token = tokenize_buffer(alloc, len, &end);
if (!token)
return NULL;
if (token_type(token) != TOKEN_STREAMBEGIN)
return NULL;
token = token->next;
ret = arg;
while (token_type(token) == TOKEN_SPECIAL &&
(token->special == SPECIAL_DEREFERENCE || token->special == '.')) {
prev = token;
token = token->next;
if (token_type(token) != TOKEN_IDENT)
return NULL;
ret = deref_expression(ret);
ret = member_expression(ret,
(prev->special == SPECIAL_DEREFERENCE) ? '*' : '.',
token->ident);
token = token->next;
}
if (token_type(token) != TOKEN_STREAMEND)
return NULL;
return ret;
}
void expr_set_parent_expr(struct expression *expr, struct expression *parent)
{
if (!expr)
return;
if (parent && parent->smatch_flags & Tmp)
return;
expr->parent = (unsigned long)parent | 0x1UL;
}
void expr_set_parent_stmt(struct expression *expr, struct statement *parent)
{
if (!expr)
return;
expr->parent = (unsigned long)parent;
}
struct expression *expr_get_parent_expr(struct expression *expr)
{
if (!expr)
return NULL;
if (!(expr->parent & 0x1UL))
return NULL;
return (struct expression *)(expr->parent & ~0x1UL);
}
struct statement *expr_get_parent_stmt(struct expression *expr)
{
if (!expr)
return NULL;
if (expr->parent & 0x1UL)
return NULL;
return (struct statement *)expr->parent;
}