mirror of
git://projects.qi-hardware.com/fped.git
synced 2024-12-22 23:14:36 +02:00
f2d3986600
/ \t/, / $/, and /\t$/
137 lines
3.1 KiB
C
137 lines
3.1 KiB
C
/*
|
|
* unparse.c - Dump an expression tree into a string
|
|
*
|
|
* Written 2009, 2012 by Werner Almesberger
|
|
* Copyright 2009, 2012 by Werner Almesberger
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*/
|
|
|
|
/*
|
|
* This is crazily inefficient but who cares :-)
|
|
*/
|
|
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
|
|
#include "util.h"
|
|
#include "expr.h"
|
|
#include "unparse.h"
|
|
|
|
|
|
enum prec {
|
|
prec_add,
|
|
prec_mult,
|
|
prec_unary,
|
|
prec_primary,
|
|
};
|
|
|
|
|
|
static int precedence(op_type op)
|
|
{
|
|
if (op == op_add || op == op_sub)
|
|
return prec_add;
|
|
if (op == op_mult || op == op_div)
|
|
return prec_mult;
|
|
if (op == op_minus)
|
|
return prec_unary;
|
|
if (op == op_num || op == op_string || op == op_var ||
|
|
op == op_sin || op == op_cos || op == op_sqrt || op == op_floor)
|
|
return prec_primary;
|
|
abort();
|
|
}
|
|
|
|
|
|
static char *merge3(char *a, const char *op, char *b)
|
|
{
|
|
char *buf;
|
|
|
|
buf = alloc_size(strlen(op)+strlen(a)+strlen(b)+1);
|
|
sprintf(buf, "%s%s%s", a, op, b);
|
|
free(a);
|
|
free(b);
|
|
return buf;
|
|
}
|
|
|
|
|
|
static char *merge2(const char *op, char *a)
|
|
{
|
|
char *buf;
|
|
|
|
buf = alloc_size(strlen(op)+strlen(a)+1);
|
|
sprintf(buf, "%s%s", op, a);
|
|
free(a);
|
|
return buf;
|
|
}
|
|
|
|
|
|
static char *unparse_op(const struct expr *expr, enum prec prec);
|
|
|
|
|
|
static char *unparse_fn(const char *name, const struct expr *expr)
|
|
{
|
|
char *buf, *tmp;
|
|
|
|
tmp = unparse_op(expr->u.op.a, prec_add);
|
|
buf = alloc_size(strlen(name)+strlen(tmp)+3);
|
|
sprintf(buf, "%s(%s)", name, tmp);
|
|
free(tmp);
|
|
return buf;
|
|
}
|
|
|
|
|
|
static char *unparse_op(const struct expr *expr, enum prec prec)
|
|
{
|
|
char tmp[100];
|
|
char *buf, *temp;
|
|
|
|
if (prec > precedence(expr->op)) {
|
|
temp = unparse_op(expr, prec_add);
|
|
buf = alloc_size(strlen(temp)+3);
|
|
sprintf(buf, "(%s)", temp);
|
|
free(temp);
|
|
return buf;
|
|
}
|
|
if (expr->op == op_num) {
|
|
snprintf(tmp, sizeof(tmp), "%lg%s",
|
|
expr->u.num.n, str_unit(expr->u.num));
|
|
return stralloc(tmp);
|
|
}
|
|
if (expr->op == op_string)
|
|
return stralloc_printf("\"%s\"", expr->u.str);
|
|
if (expr->op == op_var)
|
|
return stralloc(expr->u.var);
|
|
if (expr->op == op_minus)
|
|
return merge2("-", unparse_op(expr->u.op.a, prec_unary));
|
|
if (expr->op == op_add)
|
|
return merge3(unparse_op(expr->u.op.a, prec_add), "+",
|
|
unparse_op(expr->u.op.b, prec_add));
|
|
if (expr->op == op_sub)
|
|
return merge3(unparse_op(expr->u.op.a, prec_add), "-",
|
|
unparse_op(expr->u.op.b, prec_mult));
|
|
if (expr->op == op_mult)
|
|
return merge3(unparse_op(expr->u.op.a, prec_mult), "*",
|
|
unparse_op(expr->u.op.b, prec_mult));
|
|
if (expr->op == op_div)
|
|
return merge3(unparse_op(expr->u.op.a, prec_mult), "/",
|
|
unparse_op(expr->u.op.b, prec_primary));
|
|
if (expr->op == op_sin)
|
|
return unparse_fn("sin", expr);
|
|
if (expr->op == op_cos)
|
|
return unparse_fn("cos", expr);
|
|
if (expr->op == op_sqrt)
|
|
return unparse_fn("sqrt", expr);
|
|
if (expr->op == op_floor)
|
|
return unparse_fn("floor", expr);
|
|
abort();
|
|
}
|
|
|
|
|
|
char *unparse(const struct expr *expr)
|
|
{
|
|
return expr ? unparse_op(expr, prec_add) : stralloc("");
|
|
}
|