321 lines
4.6 KiB
C++
321 lines
4.6 KiB
C++
#include "stdafx.h"
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// Symbolic addition
|
|
//
|
|
// Input: Addends on stack
|
|
//
|
|
// Output: Result on stack
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
#include "defs.h"
|
|
|
|
extern int esc_flag;
|
|
|
|
static void __add(void);
|
|
static void combine_terms(void);
|
|
static void parse_p1(void);
|
|
static void parse_p2(void);
|
|
|
|
void
|
|
add()
|
|
{
|
|
if (esc_flag)
|
|
stop("esc");
|
|
if (tos < 2)
|
|
stop("stack underflow");
|
|
if (isnum(stack[tos - 2]) && isnum(stack[tos - 1]))
|
|
add_numbers();
|
|
else {
|
|
save();
|
|
__add();
|
|
restore();
|
|
}
|
|
}
|
|
|
|
static void
|
|
__add(void)
|
|
{
|
|
int h, n;
|
|
|
|
// pop operands
|
|
|
|
p2 = pop();
|
|
p1 = pop();
|
|
|
|
h = tos;
|
|
|
|
// is either operand nil?
|
|
|
|
if (p1 == nil || p2 == nil) {
|
|
push(nil);
|
|
return;
|
|
}
|
|
|
|
// is either operand zero?
|
|
|
|
if (iszero(p1)) {
|
|
push(p2);
|
|
return;
|
|
}
|
|
|
|
if (iszero(p2)) {
|
|
push(p1);
|
|
return;
|
|
}
|
|
|
|
// normalize operands
|
|
|
|
if (isadd(p1))
|
|
p1 = cdr(p1);
|
|
else {
|
|
push(p1);
|
|
list(1);
|
|
p1 = pop();
|
|
}
|
|
|
|
if (isadd(p2))
|
|
p2 = cdr(p2);
|
|
else {
|
|
push(p2);
|
|
list(1);
|
|
p2 = pop();
|
|
}
|
|
|
|
if (isnum(car(p1)) && isnum(car(p2))) {
|
|
push(car(p1));
|
|
push(car(p2));
|
|
add_numbers();
|
|
p7 = pop();
|
|
if (!iszero(p7))
|
|
push(p7);
|
|
p1 = cdr(p1);
|
|
p2 = cdr(p2);
|
|
}
|
|
|
|
parse_p1();
|
|
parse_p2();
|
|
|
|
while (iscons(p1) && iscons(p2)) {
|
|
|
|
if (istensor(car(p1)) && istensor(car(p2))) {
|
|
push(car(p1));
|
|
push(car(p2));
|
|
tensor_plus_tensor();
|
|
p7 = pop();
|
|
if (p7 != nil) {
|
|
push(p7);
|
|
p1 = cdr(p1);
|
|
p2 = cdr(p2);
|
|
parse_p1();
|
|
parse_p2();
|
|
continue;
|
|
}
|
|
}
|
|
|
|
switch (cmp_expr(p3, p4)) {
|
|
case -1:
|
|
push(car(p1));
|
|
p1 = cdr(p1);
|
|
parse_p1();
|
|
break;
|
|
case 1:
|
|
push(car(p2));
|
|
p2 = cdr(p2);
|
|
parse_p2();
|
|
break;
|
|
case 0:
|
|
combine_terms();
|
|
p1 = cdr(p1);
|
|
p2 = cdr(p2);
|
|
parse_p1();
|
|
parse_p2();
|
|
break;
|
|
default:
|
|
stop("internal error 1");
|
|
break;
|
|
}
|
|
}
|
|
|
|
// push remaining terms, if any
|
|
|
|
while (iscons(p1)) {
|
|
push(car(p1));
|
|
p1 = cdr(p1);
|
|
}
|
|
|
|
while (iscons(p2)) {
|
|
push(car(p2));
|
|
p2 = cdr(p2);
|
|
}
|
|
|
|
// sum of n terms
|
|
|
|
n = tos - h;
|
|
|
|
switch (n) {
|
|
case 0:
|
|
push(_zero);
|
|
break;
|
|
case 1:
|
|
break;
|
|
default:
|
|
list(n);
|
|
p7 = pop();
|
|
push_symbol(ADD);
|
|
push(p7);
|
|
cons();
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Decompose a term into numerical and non-numerical parts.
|
|
//
|
|
// input: car(p1) term
|
|
//
|
|
// output: p3 term's non-numerical factor(s)
|
|
//
|
|
// p5 term's numerical factor (possibly 1)
|
|
|
|
static void
|
|
parse_p1(void)
|
|
{
|
|
p3 = car(p1);
|
|
p5 = _one;
|
|
if (car(p3) == symbol(MULTIPLY) && isnum(cadr(p3))) {
|
|
p5 = cadr(p3);
|
|
p3 = cddr(p3);
|
|
if (cdr(p3) == nil)
|
|
p3 = car(p3);
|
|
else {
|
|
push_symbol(MULTIPLY);
|
|
push(p3);
|
|
cons();
|
|
p3 = pop();
|
|
}
|
|
}
|
|
}
|
|
|
|
// Decompose a term into numerical and non-numerical parts.
|
|
//
|
|
// input: car(p2) term
|
|
//
|
|
// output: p4 term's non-numerical factor(s)
|
|
//
|
|
// p6 term's numerical factor (possibly 1)
|
|
|
|
static void
|
|
parse_p2(void)
|
|
{
|
|
p4 = car(p2);
|
|
p6 = _one;
|
|
if (car(p4) == symbol(MULTIPLY) && isnum(cadr(p4))) {
|
|
p6 = cadr(p4);
|
|
p4 = cddr(p4);
|
|
if (cdr(p4) == nil)
|
|
p4 = car(p4);
|
|
else {
|
|
push_symbol(MULTIPLY);
|
|
push(p4);
|
|
cons();
|
|
p4 = pop();
|
|
}
|
|
}
|
|
}
|
|
|
|
// Combine two terms by adding coefficients.
|
|
//
|
|
// input: p4 Common factor or list of common factors.
|
|
//
|
|
// p5 Numeric coefficient of first term.
|
|
//
|
|
// p6 Numeric coefficient of second term.
|
|
//
|
|
// output: ((p5 + p6) * p4) on stack
|
|
//
|
|
// If result is zero then nothing is pushed on stack.
|
|
//
|
|
// p7 mangled
|
|
//
|
|
// test cases: 1 a-a (result has zero coeff)
|
|
//
|
|
// 2 2*a-a (result has unity coeff, one factor)
|
|
//
|
|
// 3 2*a*b-*a*b (result has unity coeff, two factors)
|
|
//
|
|
// 4 a+a (result has other coeff, one factor)
|
|
//
|
|
// 5 a*b+a*b (result has other coeff, two factors)
|
|
|
|
static void
|
|
combine_terms(void)
|
|
{
|
|
push(p5);
|
|
push(p6);
|
|
add_numbers();
|
|
p7 = pop();
|
|
if (iszero(p7))
|
|
return;
|
|
if (isplusone(p7)) {
|
|
push(p4);
|
|
return;
|
|
}
|
|
if (car(p4) == symbol(MULTIPLY)) {
|
|
push(car(p4));
|
|
push(p7);
|
|
push(cdr(p4));
|
|
cons();
|
|
cons();
|
|
return;
|
|
}
|
|
push_symbol(MULTIPLY);
|
|
push(p7);
|
|
push(p4);
|
|
list(3);
|
|
}
|
|
|
|
void
|
|
addk(int k)
|
|
{
|
|
int h, i;
|
|
if (k == 1)
|
|
return;
|
|
if (k == 0) {
|
|
push(_zero);
|
|
return;
|
|
}
|
|
h = tos - k;
|
|
push(stack[h]);
|
|
for (i = 1; i < k; i++) {
|
|
push(stack[h + i]);
|
|
add();
|
|
}
|
|
stack[h] = pop();
|
|
tos = h + 1;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// Symbolic subtraction
|
|
//
|
|
// Input: Minuend and subtrahend on stack
|
|
//
|
|
// Output: Result on stack
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
void
|
|
subtract(void)
|
|
{
|
|
if (tos < 2)
|
|
stop("stack underflow");
|
|
if (isnum(stack[tos - 2]) && isnum(stack[tos - 1]))
|
|
subtract_numbers();
|
|
else {
|
|
negate();
|
|
add();
|
|
}
|
|
}
|