1285 lines
18 KiB
C++
1285 lines
18 KiB
C++
//-----------------------------------------------------------------------------
|
|
//
|
|
// Examples:
|
|
//
|
|
// 012345678
|
|
// -2 .........
|
|
// -1 .........
|
|
// 0 ..hello.. x=2, y=0, h=1, w=5
|
|
// 1 .........
|
|
// 2 .........
|
|
//
|
|
// 012345678
|
|
// -2 .........
|
|
// -1 ..355....
|
|
// 0 ..---.... x=2, y=-1, h=3, w=3
|
|
// 1 ..113....
|
|
// 2 .........
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
#include "stdafx.h"
|
|
#include "defs.h"
|
|
|
|
#define YMAX 10000
|
|
struct glyph {
|
|
int c, x, y;
|
|
} chartab[YMAX];
|
|
|
|
static void emit_expr(U *);
|
|
static void emit_term(U *);
|
|
static void emit_multiply(U *, int);
|
|
static void emit_factor(U *);
|
|
static void emit_power(U *);
|
|
static void emit_denominator(U *, int);
|
|
static void emit_subexpr(U *);
|
|
static void fixup_power(int, int);
|
|
static void move(int, int, int, int);
|
|
static void get_size(int, int, int *, int *, int *);
|
|
static void emit_function(U *);
|
|
static void emit_symbol(U *);
|
|
static void emit_string(U *);
|
|
static void __emit_char(int);
|
|
static void __emit_str(char *);
|
|
static void print_it();
|
|
static int count_denominators(U *);
|
|
static int __is_negative(U *);
|
|
static void emit_fraction(U *, int);
|
|
static void emit_numerical_fraction(U *);
|
|
static void emit_tensor(U *);
|
|
static int isdenominator(U *p);
|
|
static void emit_flat_tensor(U *);
|
|
static void emit_tensor_inner(U *, int, int *);
|
|
static void emit_top_expr(U *);
|
|
static void emit_index_function(U *);
|
|
static void emit_factorial_function(U *);
|
|
static void emit_numerators(U *);
|
|
static void emit_denominators(U *);
|
|
|
|
static int yindex, level, emit_x;
|
|
static int expr_level;
|
|
int display_flag;
|
|
|
|
void
|
|
display(U *p)
|
|
{
|
|
int h, w, y;
|
|
|
|
save();
|
|
|
|
yindex = 0;
|
|
level = 0;
|
|
emit_x = 0;
|
|
emit_top_expr(p);
|
|
|
|
// if too wide then print flat
|
|
|
|
get_size(0, yindex, &h, &w, &y);
|
|
|
|
if (w > 100) {
|
|
printline(p);
|
|
restore();
|
|
return;
|
|
}
|
|
|
|
print_it();
|
|
|
|
restore();
|
|
}
|
|
|
|
static void
|
|
emit_top_expr(U *p)
|
|
{
|
|
if (car(p) == symbol(SETQ)) {
|
|
emit_expr(cadr(p));
|
|
__emit_str(" = ");
|
|
emit_expr(caddr(p));
|
|
return;
|
|
}
|
|
|
|
if (istensor(p))
|
|
emit_tensor(p);
|
|
else
|
|
emit_expr(p);
|
|
}
|
|
|
|
static int
|
|
will_be_displayed_as_fraction(U *p)
|
|
{
|
|
if (level > 0)
|
|
return 0;
|
|
if (isfraction(p))
|
|
return 1;
|
|
if (car(p) != symbol(MULTIPLY))
|
|
return 0;
|
|
if (isfraction(cadr(p)))
|
|
return 1;
|
|
while (iscons(p)) {
|
|
if (isdenominator(car(p)))
|
|
return 1;
|
|
p = cdr(p);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static void
|
|
emit_expr(U *p)
|
|
{
|
|
// if (level > 0) {
|
|
// printexpr(p);
|
|
// return;
|
|
// }
|
|
expr_level++;
|
|
if (car(p) == symbol(ADD)) {
|
|
p = cdr(p);
|
|
if (__is_negative(car(p))) {
|
|
__emit_char('-');
|
|
if (will_be_displayed_as_fraction(car(p)))
|
|
__emit_char(' ');
|
|
}
|
|
emit_term(car(p));
|
|
p = cdr(p);
|
|
while (iscons(p)) {
|
|
if (__is_negative(car(p))) {
|
|
//if (expr_level == 1)
|
|
__emit_char(' ');
|
|
__emit_char('-');
|
|
//if (expr_level == 1)
|
|
__emit_char(' ');
|
|
} else {
|
|
//if (expr_level == 1)
|
|
__emit_char(' ');
|
|
__emit_char('+');
|
|
//if (expr_level == 1)
|
|
__emit_char(' ');
|
|
}
|
|
emit_term(car(p));
|
|
p = cdr(p);
|
|
}
|
|
} else {
|
|
if (__is_negative(p)) {
|
|
__emit_char('-');
|
|
if (will_be_displayed_as_fraction(p))
|
|
__emit_char(' ');
|
|
}
|
|
emit_term(p);
|
|
}
|
|
expr_level--;
|
|
}
|
|
|
|
static void
|
|
emit_unsigned_expr(U *p)
|
|
{
|
|
if (car(p) == symbol(ADD)) {
|
|
p = cdr(p);
|
|
// if (__is_negative(car(p)))
|
|
// __emit_char('-');
|
|
emit_term(car(p));
|
|
p = cdr(p);
|
|
while (iscons(p)) {
|
|
if (__is_negative(car(p))) {
|
|
__emit_char(' ');
|
|
__emit_char('-');
|
|
__emit_char(' ');
|
|
} else {
|
|
__emit_char(' ');
|
|
__emit_char('+');
|
|
__emit_char(' ');
|
|
}
|
|
emit_term(car(p));
|
|
p = cdr(p);
|
|
}
|
|
} else {
|
|
// if (__is_negative(p))
|
|
// __emit_char('-');
|
|
emit_term(p);
|
|
}
|
|
}
|
|
|
|
static int
|
|
__is_negative(U *p)
|
|
{
|
|
if (isnegativenumber(p))
|
|
return 1;
|
|
if (car(p) == symbol(MULTIPLY) && isnegativenumber(cadr(p)))
|
|
return 1;
|
|
return 0;
|
|
}
|
|
|
|
static void
|
|
emit_term(U *p)
|
|
{
|
|
int n;
|
|
if (car(p) == symbol(MULTIPLY)) {
|
|
n = count_denominators(p);
|
|
if (n && level == 0)
|
|
emit_fraction(p, n);
|
|
else
|
|
emit_multiply(p, n);
|
|
} else
|
|
emit_factor(p);
|
|
}
|
|
|
|
static int
|
|
isdenominator(U *p)
|
|
{
|
|
if (car(p) == symbol(POWER) && cadr(p) != symbol(E) && __is_negative(caddr(p)))
|
|
return 1;
|
|
else
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
count_denominators(U *p)
|
|
{
|
|
int count = 0;
|
|
U *q;
|
|
p = cdr(p);
|
|
// if (isfraction(car(p))) {
|
|
// count++;
|
|
// p = cdr(p);
|
|
// }
|
|
while (iscons(p)) {
|
|
q = car(p);
|
|
if (isdenominator(q))
|
|
count++;
|
|
p = cdr(p);
|
|
}
|
|
return count;
|
|
}
|
|
|
|
// n is the number of denominators, not counting a fraction like 1/2
|
|
|
|
static void
|
|
emit_multiply(U *p, int n)
|
|
{
|
|
if (n == 0) {
|
|
p = cdr(p);
|
|
if (isplusone(car(p)) || isminusone(car(p)))
|
|
p = cdr(p);
|
|
emit_factor(car(p));
|
|
p = cdr(p);
|
|
while (iscons(p)) {
|
|
__emit_char(' ');
|
|
emit_factor(car(p));
|
|
p = cdr(p);
|
|
}
|
|
} else {
|
|
emit_numerators(p);
|
|
__emit_char('/');
|
|
// need grouping if more than one denominator
|
|
if (n > 1 || isfraction(cadr(p))) {
|
|
__emit_char('(');
|
|
emit_denominators(p);
|
|
__emit_char(')');
|
|
} else
|
|
emit_denominators(p);
|
|
}
|
|
}
|
|
|
|
#define A p3
|
|
#define B p4
|
|
|
|
// sign of term has already been emitted
|
|
|
|
static void
|
|
emit_fraction(U *p, int d)
|
|
{
|
|
int count, k1, k2, n, x;
|
|
|
|
save();
|
|
|
|
A = one;
|
|
B = one;
|
|
|
|
// handle numerical coefficient
|
|
|
|
if (isrational(cadr(p))) {
|
|
push(cadr(p));
|
|
mp_numerator();
|
|
absval();
|
|
A = pop();
|
|
push(cadr(p));
|
|
mp_denominator();
|
|
B = pop();
|
|
}
|
|
|
|
if (isdouble(cadr(p))) {
|
|
push(cadr(p));
|
|
absval();
|
|
A = pop();
|
|
}
|
|
|
|
// count numerators
|
|
|
|
if (isplusone(A))
|
|
n = 0;
|
|
else
|
|
n = 1;
|
|
p1 = cdr(p);
|
|
if (isnum(car(p1)))
|
|
p1 = cdr(p1);
|
|
while (iscons(p1)) {
|
|
p2 = car(p1);
|
|
if (isdenominator(p2))
|
|
;
|
|
else
|
|
n++;
|
|
p1 = cdr(p1);
|
|
}
|
|
|
|
// emit numerators
|
|
|
|
x = emit_x;
|
|
|
|
k1 = yindex;
|
|
|
|
count = 0;
|
|
|
|
// emit numerical coefficient
|
|
|
|
if (!isplusone(A)) {
|
|
emit_number(A, 0);
|
|
count++;
|
|
}
|
|
|
|
// skip over "multiply"
|
|
|
|
p1 = cdr(p);
|
|
|
|
// skip over numerical coefficient, already handled
|
|
|
|
if (isnum(car(p1)))
|
|
p1 = cdr(p1);
|
|
|
|
while (iscons(p1)) {
|
|
p2 = car(p1);
|
|
if (isdenominator(p2))
|
|
;
|
|
else {
|
|
if (count > 0)
|
|
__emit_char(' ');
|
|
if (n == 1)
|
|
emit_expr(p2);
|
|
else
|
|
emit_factor(p2);
|
|
count++;
|
|
}
|
|
p1 = cdr(p1);
|
|
}
|
|
|
|
if (count == 0)
|
|
__emit_char('1');
|
|
|
|
// emit denominators
|
|
|
|
k2 = yindex;
|
|
|
|
count = 0;
|
|
|
|
if (!isplusone(B)) {
|
|
emit_number(B, 0);
|
|
count++;
|
|
d++;
|
|
}
|
|
|
|
p1 = cdr(p);
|
|
|
|
if (isrational(car(p1)))
|
|
p1 = cdr(p1);
|
|
|
|
while (iscons(p1)) {
|
|
p2 = car(p1);
|
|
if (isdenominator(p2)) {
|
|
if (count > 0)
|
|
__emit_char(' ');
|
|
emit_denominator(p2, d);
|
|
count++;
|
|
}
|
|
p1 = cdr(p1);
|
|
}
|
|
|
|
fixup_fraction(x, k1, k2);
|
|
|
|
restore();
|
|
}
|
|
|
|
// p points to a multiply
|
|
|
|
static void
|
|
emit_numerators(U *p)
|
|
{
|
|
int n;
|
|
|
|
save();
|
|
|
|
p1 = one;
|
|
|
|
p = cdr(p);
|
|
|
|
if (isrational(car(p))) {
|
|
push(car(p));
|
|
mp_numerator();
|
|
absval();
|
|
p1 = pop();
|
|
p = cdr(p);
|
|
} else if (isdouble(car(p))) {
|
|
push(car(p));
|
|
absval();
|
|
p1 = pop();
|
|
p = cdr(p);
|
|
}
|
|
|
|
n = 0;
|
|
|
|
if (!isplusone(p1)) {
|
|
emit_number(p1, 0);
|
|
n++;
|
|
}
|
|
|
|
while (iscons(p)) {
|
|
if (isdenominator(car(p)))
|
|
;
|
|
else {
|
|
if (n > 0)
|
|
__emit_char(' ');
|
|
emit_factor(car(p));
|
|
n++;
|
|
}
|
|
p = cdr(p);
|
|
}
|
|
|
|
if (n == 0)
|
|
__emit_char('1');
|
|
|
|
restore();
|
|
}
|
|
|
|
// p points to a multiply
|
|
|
|
static void
|
|
emit_denominators(U *p)
|
|
{
|
|
int n;
|
|
|
|
save();
|
|
|
|
n = 0;
|
|
|
|
p = cdr(p);
|
|
|
|
if (isfraction(car(p))) {
|
|
push(car(p));
|
|
mp_denominator();
|
|
p1 = pop();
|
|
emit_number(p1, 0);
|
|
n++;
|
|
p = cdr(p);
|
|
}
|
|
|
|
while (iscons(p)) {
|
|
if (isdenominator(car(p))) {
|
|
if (n > 0)
|
|
__emit_char(' ');
|
|
emit_denominator(car(p), 0);
|
|
n++;
|
|
}
|
|
p = cdr(p);
|
|
}
|
|
|
|
restore();
|
|
}
|
|
|
|
static void
|
|
emit_factor(U *p)
|
|
{
|
|
if (istensor(p)) {
|
|
if (level == 0)
|
|
//emit_tensor(p);
|
|
emit_flat_tensor(p);
|
|
else
|
|
emit_flat_tensor(p);
|
|
return;
|
|
}
|
|
|
|
if (isdouble(p)) {
|
|
emit_number(p, 0);
|
|
return;
|
|
}
|
|
|
|
if (car(p) == symbol(ADD) || car(p) == symbol(MULTIPLY)) {
|
|
emit_subexpr(p);
|
|
return;
|
|
}
|
|
|
|
if (car(p) == symbol(POWER)) {
|
|
emit_power(p);
|
|
return;
|
|
}
|
|
|
|
if (iscons(p)) {
|
|
//if (car(p) == symbol(FORMAL) && cadr(p)->k == SYM)
|
|
// emit_symbol(cadr(p));
|
|
//else
|
|
emit_function(p);
|
|
return;
|
|
}
|
|
|
|
if (isnum(p)) {
|
|
if (level == 0)
|
|
emit_numerical_fraction(p);
|
|
else
|
|
emit_number(p, 0);
|
|
return;
|
|
}
|
|
|
|
if (issymbol(p)) {
|
|
emit_symbol(p);
|
|
return;
|
|
}
|
|
|
|
if (isstr(p)) {
|
|
emit_string(p);
|
|
return;
|
|
}
|
|
}
|
|
|
|
static void
|
|
emit_numerical_fraction(U *p)
|
|
{
|
|
int k1, k2, x;
|
|
|
|
save();
|
|
|
|
push(p);
|
|
mp_numerator();
|
|
absval();
|
|
A = pop();
|
|
|
|
push(p);
|
|
mp_denominator();
|
|
B = pop();
|
|
|
|
if (isplusone(B)) {
|
|
emit_number(A, 0);
|
|
restore();
|
|
return;
|
|
}
|
|
|
|
x = emit_x;
|
|
|
|
k1 = yindex;
|
|
|
|
emit_number(A, 0);
|
|
|
|
k2 = yindex;
|
|
|
|
emit_number(B, 0);
|
|
|
|
fixup_fraction(x, k1, k2);
|
|
|
|
restore();
|
|
}
|
|
|
|
// if it's a factor then it doesn't need parens around it, i.e. 1/sin(theta)^2
|
|
|
|
static int
|
|
isfactor(U *p)
|
|
{
|
|
if (iscons(p) && car(p) != symbol(ADD) && car(p) != symbol(MULTIPLY) && car(p) != symbol(POWER))
|
|
return 1;
|
|
if (issymbol(p))
|
|
return 1;
|
|
if (isfraction(p))
|
|
return 0;
|
|
if (isnegativenumber(p))
|
|
return 0;
|
|
if (isnum(p))
|
|
return 1;
|
|
return 0;
|
|
}
|
|
|
|
static void
|
|
emit_power(U *p)
|
|
{
|
|
int k1, k2, x;
|
|
|
|
if (cadr(p) == symbol(E)) {
|
|
__emit_str("exp(");
|
|
emit_expr(caddr(p));
|
|
__emit_char(')');
|
|
return;
|
|
}
|
|
|
|
if (level > 0) {
|
|
if (isminusone(caddr(p))) {
|
|
__emit_char('1');
|
|
__emit_char('/');
|
|
if (isfactor(cadr(p)))
|
|
emit_factor(cadr(p));
|
|
else
|
|
emit_subexpr(cadr(p));
|
|
} else {
|
|
if (isfactor(cadr(p)))
|
|
emit_factor(cadr(p));
|
|
else
|
|
emit_subexpr(cadr(p));
|
|
__emit_char('^');
|
|
if (isfactor(caddr(p)))
|
|
emit_factor(caddr(p));
|
|
else
|
|
emit_subexpr(caddr(p));
|
|
}
|
|
return;
|
|
}
|
|
|
|
// special case: 1 over something
|
|
|
|
if (__is_negative(caddr(p))) {
|
|
x = emit_x;
|
|
k1 = yindex;
|
|
__emit_char('1');
|
|
k2 = yindex;
|
|
//level++;
|
|
emit_denominator(p, 1);
|
|
//level--;
|
|
fixup_fraction(x, k1, k2);
|
|
return;
|
|
}
|
|
|
|
k1 = yindex;
|
|
if (isfactor(cadr(p)))
|
|
emit_factor(cadr(p));
|
|
else
|
|
emit_subexpr(cadr(p));
|
|
k2 = yindex;
|
|
level++;
|
|
emit_expr(caddr(p));
|
|
level--;
|
|
fixup_power(k1, k2);
|
|
}
|
|
|
|
// if n == 1 then emit as expr (no parens)
|
|
|
|
// p is a power
|
|
|
|
static void
|
|
emit_denominator(U *p, int n)
|
|
{
|
|
int k1, k2;
|
|
|
|
// special case: 1 over something
|
|
|
|
if (isminusone(caddr(p))) {
|
|
if (n == 1)
|
|
emit_expr(cadr(p));
|
|
else
|
|
emit_factor(cadr(p));
|
|
return;
|
|
}
|
|
|
|
k1 = yindex;
|
|
|
|
// emit base
|
|
|
|
if (isfactor(cadr(p)))
|
|
emit_factor(cadr(p));
|
|
else
|
|
emit_subexpr(cadr(p));
|
|
|
|
k2 = yindex;
|
|
|
|
// emit exponent, don't emit minus sign
|
|
|
|
level++;
|
|
|
|
emit_unsigned_expr(caddr(p));
|
|
|
|
level--;
|
|
|
|
fixup_power(k1, k2);
|
|
}
|
|
|
|
static void
|
|
emit_function(U *p)
|
|
{
|
|
if (car(p) == symbol(INDEX) && issymbol(cadr(p))) {
|
|
emit_index_function(p);
|
|
return;
|
|
}
|
|
|
|
if (car(p) == symbol(FACTORIAL)) {
|
|
emit_factorial_function(p);
|
|
return;
|
|
}
|
|
|
|
if (car(p) == symbol(DERIVATIVE))
|
|
__emit_char('d');
|
|
else
|
|
emit_symbol(car(p));
|
|
__emit_char('(');
|
|
p = cdr(p);
|
|
if (iscons(p)) {
|
|
emit_expr(car(p));
|
|
p = cdr(p);
|
|
while (iscons(p)) {
|
|
__emit_char(',');
|
|
//__emit_char(' ');
|
|
emit_expr(car(p));
|
|
p = cdr(p);
|
|
}
|
|
}
|
|
__emit_char(')');
|
|
}
|
|
|
|
static void
|
|
emit_index_function(U *p)
|
|
{
|
|
p = cdr(p);
|
|
if (caar(p) == symbol(ADD) || caar(p) == symbol(MULTIPLY) || caar(p) == symbol(POWER) || caar(p) == symbol(FACTORIAL))
|
|
emit_subexpr(car(p));
|
|
else
|
|
emit_expr(car(p));
|
|
__emit_char('[');
|
|
p = cdr(p);
|
|
if (iscons(p)) {
|
|
emit_expr(car(p));
|
|
p = cdr(p);
|
|
while(iscons(p)) {
|
|
__emit_char(',');
|
|
emit_expr(car(p));
|
|
p = cdr(p);
|
|
}
|
|
}
|
|
__emit_char(']');
|
|
}
|
|
|
|
static void
|
|
emit_factorial_function(U *p)
|
|
{
|
|
p = cadr(p);
|
|
if (car(p) == symbol(ADD) || car(p) == symbol(MULTIPLY) || car(p) == symbol(POWER) || car(p) == symbol(FACTORIAL))
|
|
emit_subexpr(p);
|
|
else
|
|
emit_expr(p);
|
|
__emit_char('!');
|
|
}
|
|
|
|
static void
|
|
emit_subexpr(U *p)
|
|
{
|
|
__emit_char('(');
|
|
emit_expr(p);
|
|
__emit_char(')');
|
|
}
|
|
|
|
static void
|
|
emit_symbol(U *p)
|
|
{
|
|
char *s;
|
|
|
|
if (p == symbol(E)) {
|
|
__emit_str("exp(1)");
|
|
return;
|
|
}
|
|
|
|
s = get_printname(p);
|
|
while (*s)
|
|
__emit_char(*s++);
|
|
}
|
|
|
|
static void
|
|
emit_string(U *p)
|
|
{
|
|
char *s;
|
|
s = p->u.str;
|
|
while (*s)
|
|
__emit_char(*s++);
|
|
}
|
|
|
|
void
|
|
fixup_fraction(int x, int k1, int k2)
|
|
{
|
|
int dx, dy, i, w, y;
|
|
int h1, w1, y1;
|
|
int h2, w2, y2;
|
|
|
|
get_size(k1, k2, &h1, &w1, &y1);
|
|
get_size(k2, yindex, &h2, &w2, &y2);
|
|
|
|
if (w2 > w1)
|
|
dx = (w2 - w1) / 2; // shift numerator right
|
|
else
|
|
dx = 0;
|
|
dx++;
|
|
// this is how much is below the baseline
|
|
|
|
y = y1 + h1 - 1;
|
|
|
|
dy = -y - 1;
|
|
|
|
move(k1, k2, dx, dy);
|
|
|
|
if (w2 > w1)
|
|
dx = -w1;
|
|
else
|
|
dx = -w1 + (w1 - w2) / 2;
|
|
dx++;
|
|
dy = -y2 + 1;
|
|
|
|
move(k2, yindex, dx, dy);
|
|
|
|
if (w2 > w1)
|
|
w = w2;
|
|
else
|
|
w = w1;
|
|
w+=2;
|
|
emit_x = x;
|
|
|
|
for (i = 0; i < w; i++)
|
|
__emit_char('-');
|
|
}
|
|
|
|
static void
|
|
fixup_power(int k1, int k2)
|
|
{
|
|
int dy;
|
|
int h1, w1, y1;
|
|
int h2, w2, y2;
|
|
|
|
get_size(k1, k2, &h1, &w1, &y1);
|
|
get_size(k2, yindex, &h2, &w2, &y2);
|
|
|
|
// move superscript to baseline
|
|
|
|
dy = -y2 - h2 + 1;
|
|
|
|
// now move above base
|
|
|
|
dy += y1 - 1;
|
|
|
|
move(k2, yindex, 0, dy);
|
|
}
|
|
|
|
static void
|
|
move(int j, int k, int dx, int dy)
|
|
{
|
|
int i;
|
|
for (i = j; i < k; i++) {
|
|
chartab[i].x += dx;
|
|
chartab[i].y += dy;
|
|
}
|
|
}
|
|
|
|
// finds the bounding rectangle and vertical position
|
|
|
|
static void
|
|
get_size(int j, int k, int *h, int *w, int *y)
|
|
{
|
|
int i;
|
|
int min_x, max_x, min_y, max_y;
|
|
min_x = chartab[j].x;
|
|
max_x = chartab[j].x;
|
|
min_y = chartab[j].y;
|
|
max_y = chartab[j].y;
|
|
for (i = j + 1; i < k; i++) {
|
|
if (chartab[i].x < min_x)
|
|
min_x = chartab[i].x;
|
|
if (chartab[i].x > max_x)
|
|
max_x = chartab[i].x;
|
|
if (chartab[i].y < min_y)
|
|
min_y = chartab[i].y;
|
|
if (chartab[i].y > max_y)
|
|
max_y = chartab[i].y;
|
|
}
|
|
*h = max_y - min_y + 1;
|
|
*w = max_x - min_x + 1;
|
|
*y = min_y;
|
|
}
|
|
|
|
void
|
|
displaychar(int c)
|
|
{
|
|
__emit_char(c);
|
|
}
|
|
|
|
static void
|
|
__emit_char(int c)
|
|
{
|
|
if (yindex == YMAX)
|
|
return;
|
|
chartab[yindex].c = c;
|
|
chartab[yindex].x = emit_x;
|
|
chartab[yindex].y = 0;
|
|
yindex++;
|
|
emit_x++;
|
|
}
|
|
|
|
static void
|
|
__emit_str(char *s)
|
|
{
|
|
while (*s)
|
|
__emit_char(*s++);
|
|
}
|
|
|
|
void
|
|
emit_number(U *p, int emit_sign)
|
|
{
|
|
char *s;
|
|
static char buf[100];
|
|
switch (p->k) {
|
|
case NUM:
|
|
s = mstr(p->u.q.a);
|
|
if (*s == '-' && emit_sign == 0)
|
|
s++;
|
|
while (*s)
|
|
__emit_char(*s++);
|
|
s = mstr(p->u.q.b);
|
|
if (strcmp(s, "1") == 0)
|
|
break;
|
|
__emit_char('/');
|
|
while (*s)
|
|
__emit_char(*s++);
|
|
break;
|
|
case DOUBLE:
|
|
sprintf(buf, "%g", p->u.d);
|
|
s = buf;
|
|
if (*s == '-' && emit_sign == 0)
|
|
s++;
|
|
while (*s)
|
|
__emit_char(*s++);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
static int
|
|
__cmp(const void *aa, const void *bb)
|
|
{
|
|
struct glyph *a, *b;
|
|
|
|
a = (struct glyph *) aa;
|
|
b = (struct glyph *) bb;
|
|
|
|
if (a->y < b->y)
|
|
return -1;
|
|
|
|
if (a->y > b->y)
|
|
return 1;
|
|
|
|
if (a->x < b->x)
|
|
return -1;
|
|
|
|
if (a->x > b->x)
|
|
return 1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void
|
|
print_it(void)
|
|
{
|
|
int i, x, y;
|
|
|
|
qsort(chartab, yindex, sizeof (struct glyph), __cmp);
|
|
|
|
x = 0;
|
|
|
|
y = chartab[0].y;
|
|
|
|
for (i = 0; i < yindex; i++) {
|
|
|
|
while (chartab[i].y > y) {
|
|
printchar('\n');
|
|
x = 0;
|
|
y++;
|
|
}
|
|
|
|
while (chartab[i].x > x) {
|
|
printchar_nowrap(' ');
|
|
x++;
|
|
}
|
|
|
|
printchar_nowrap(chartab[i].c);
|
|
|
|
x++;
|
|
}
|
|
|
|
printchar('\n');
|
|
}
|
|
|
|
static void fill_buf(void);
|
|
|
|
static char buffer[10000];
|
|
|
|
char *
|
|
getdisplaystr(void)
|
|
{
|
|
yindex = 0;
|
|
level = 0;
|
|
emit_x = 0;
|
|
emit_expr(pop());
|
|
fill_buf();
|
|
return buffer;
|
|
}
|
|
|
|
static void
|
|
fill_buf(void)
|
|
{
|
|
int i, x, y;
|
|
char *s = buffer;
|
|
|
|
qsort(chartab, yindex, sizeof (struct glyph), __cmp);
|
|
|
|
x = 0;
|
|
|
|
y = chartab[0].y;
|
|
|
|
for (i = 0; i < yindex; i++) {
|
|
|
|
while (chartab[i].y > y) {
|
|
*s++ = '\n';
|
|
x = 0;
|
|
y++;
|
|
}
|
|
|
|
while (chartab[i].x > x) {
|
|
*s++ = ' ';
|
|
x++;
|
|
}
|
|
|
|
*s++ = chartab[i].c;
|
|
|
|
x++;
|
|
}
|
|
|
|
*s++ = '\n';
|
|
|
|
*s++ = '\0';
|
|
}
|
|
|
|
#define N 100
|
|
|
|
struct elem {
|
|
int x, y, h, w, index, count;
|
|
} elem[N];
|
|
|
|
#define SPACE_BETWEEN_COLUMNS 3
|
|
#define SPACE_BETWEEN_ROWS 1
|
|
|
|
static void
|
|
emit_tensor(U *p)
|
|
{
|
|
int i, n, nrow, ncol;
|
|
int x, y;
|
|
int h, w;
|
|
int dx, dy;
|
|
int eh, ew;
|
|
int row, col;
|
|
|
|
if (p->u.tensor->ndim > 2) {
|
|
emit_flat_tensor(p);
|
|
return;
|
|
}
|
|
|
|
nrow = p->u.tensor->dim[0];
|
|
|
|
if (p->u.tensor->ndim == 2)
|
|
ncol = p->u.tensor->dim[1];
|
|
else
|
|
ncol = 1;
|
|
|
|
n = nrow * ncol;
|
|
|
|
if (n > N) {
|
|
emit_flat_tensor(p);
|
|
return;
|
|
}
|
|
|
|
// horizontal coordinate of the matrix
|
|
|
|
#if 0
|
|
emit_x += 2; // make space for left paren
|
|
#endif
|
|
|
|
x = emit_x;
|
|
|
|
// emit each element
|
|
|
|
for (i = 0; i < n; i++) {
|
|
elem[i].index = yindex;
|
|
elem[i].x = emit_x;
|
|
emit_expr(p->u.tensor->elem[i]);
|
|
elem[i].count = yindex - elem[i].index;
|
|
get_size(elem[i].index, yindex, &elem[i].h, &elem[i].w, &elem[i].y);
|
|
}
|
|
|
|
// find element height and width
|
|
|
|
eh = 0;
|
|
ew = 0;
|
|
|
|
for (i = 0; i < n; i++) {
|
|
if (elem[i].h > eh)
|
|
eh = elem[i].h;
|
|
if (elem[i].w > ew)
|
|
ew = elem[i].w;
|
|
}
|
|
|
|
// this is the overall height of the matrix
|
|
|
|
h = nrow * eh + (nrow - 1) * SPACE_BETWEEN_ROWS;
|
|
|
|
// this is the overall width of the matrix
|
|
|
|
w = ncol * ew + (ncol - 1) * SPACE_BETWEEN_COLUMNS;
|
|
|
|
// this is the vertical coordinate of the matrix
|
|
|
|
y = -(h / 2);
|
|
|
|
// move elements around
|
|
|
|
for (row = 0; row < nrow; row++) {
|
|
for (col = 0; col < ncol; col++) {
|
|
|
|
i = row * ncol + col;
|
|
|
|
// first move to upper left corner of matrix
|
|
|
|
dx = x - elem[i].x;
|
|
dy = y - elem[i].y;
|
|
|
|
move(elem[i].index, elem[i].index + elem[i].count, dx, dy);
|
|
|
|
// now move to official position
|
|
|
|
dx = 0;
|
|
|
|
if (col > 0)
|
|
dx = col * (ew + SPACE_BETWEEN_COLUMNS);
|
|
|
|
dy = 0;
|
|
|
|
if (row > 0)
|
|
dy = row * (eh + SPACE_BETWEEN_ROWS);
|
|
|
|
// small correction for horizontal centering
|
|
|
|
dx += (ew - elem[i].w) / 2;
|
|
|
|
// small correction for vertical centering
|
|
|
|
dy += (eh - elem[i].h) / 2;
|
|
|
|
move(elem[i].index, elem[i].index + elem[i].count, dx, dy);
|
|
}
|
|
}
|
|
|
|
emit_x = x + w;
|
|
|
|
#if 0
|
|
|
|
// left brace
|
|
|
|
for (i = 0; i < h; i++) {
|
|
if (yindex == YMAX)
|
|
break;
|
|
chartab[yindex].c = '|';
|
|
chartab[yindex].x = x - 2;
|
|
chartab[yindex].y = y + i;
|
|
yindex++;
|
|
}
|
|
|
|
// right brace
|
|
|
|
emit_x++;
|
|
|
|
for (i = 0; i < h; i++) {
|
|
if (yindex == YMAX)
|
|
break;
|
|
chartab[yindex].c = '|';
|
|
chartab[yindex].x = emit_x;
|
|
chartab[yindex].y = y + i;
|
|
yindex++;
|
|
}
|
|
|
|
emit_x++;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
static void
|
|
emit_flat_tensor(U *p)
|
|
{
|
|
int k = 0;
|
|
emit_tensor_inner(p, 0, &k);
|
|
}
|
|
|
|
static void
|
|
emit_tensor_inner(U *p, int j, int *k)
|
|
{
|
|
int i;
|
|
__emit_char('(');
|
|
for (i = 0; i < p->u.tensor->dim[j]; i++) {
|
|
if (j + 1 == p->u.tensor->ndim) {
|
|
emit_expr(p->u.tensor->elem[*k]);
|
|
*k = *k + 1;
|
|
} else
|
|
emit_tensor_inner(p, j + 1, k);
|
|
if (i + 1 < p->u.tensor->dim[j])
|
|
__emit_char(',');
|
|
}
|
|
__emit_char(')');
|
|
}
|
|
|
|
#if SELFTEST
|
|
|
|
static char *s[] = {
|
|
|
|
"format=1",
|
|
"",
|
|
|
|
"((a,b),(c,d))",
|
|
"a b\n"
|
|
"\n"
|
|
"c d",
|
|
|
|
"1/sqrt(-15)",
|
|
|
|
" i\n"
|
|
"- -----------\n"
|
|
" 1/2 1/2\n"
|
|
" 3 5",
|
|
|
|
"x^(1/a)",
|
|
|
|
" 1/a\n"
|
|
"x",
|
|
|
|
"x^(a/b)",
|
|
|
|
" a/b\n"
|
|
"x",
|
|
|
|
"x^(a/2)",
|
|
|
|
" 1/2 a\n"
|
|
"x",
|
|
|
|
"x^(1/(a+b))",
|
|
|
|
" 1/(a + b)\n"
|
|
"x",
|
|
};
|
|
|
|
void
|
|
test_display(void)
|
|
{
|
|
test(__FILE__, s, sizeof s / sizeof (char *));
|
|
}
|
|
|
|
#endif
|