power_str = "^"
codeGen = false

# this is only invoked when user invokes
# "print" explicitly
Eval_print = ->
	stringsEmittedByUserPrintouts += _print(cdr(p1),environment_printmode)
	push(symbol(NIL));

# this is only invoked when user invokes
# "print2dascii" explicitly
Eval_print2dascii = ->
	stringsEmittedByUserPrintouts +=_print(cdr(p1),PRINTMODE_2DASCII)
	push(symbol(NIL));

# this is only invoked when user invokes
# "printfull" explicitly
Eval_printfull = ->
	stringsEmittedByUserPrintouts +=_print(cdr(p1),PRINTMODE_FULL)
	push(symbol(NIL));

# this is only invoked when user invokes
# "printlatex" explicitly
Eval_printlatex = ->
	stringsEmittedByUserPrintouts +=_print(cdr(p1),PRINTMODE_LATEX)
	push(symbol(NIL));

# this is only invoked when user invokes
# "printplain" explicitly
Eval_printplain = ->
	# test flag needs to be suspended
	# because otherwise "printfull" mode
	# will happen.
	original_test_flag = test_flag
	test_flag = 0
	stringsEmittedByUserPrintouts +=_print(cdr(p1),PRINTMODE_PLAIN)
	test_flag = original_test_flag
	push(symbol(NIL));

# this is only invoked when user invokes
# "printlist" explicitly
Eval_printlist = ->	
	beenPrinted = _print(cdr(p1),PRINTMODE_LIST)
	stringsEmittedByUserPrintouts += beenPrinted
	push(symbol(NIL))	


_print = (p, passedPrintMode) ->
	accumulator = ""

	while (iscons(p))

		push(car(p));
		Eval();
		p2 = pop();

		# display single symbol as "symbol = result"

		# but don't display "symbol = symbol"

		###
		if (issymbol(car(p)) && car(p) != p2)
			push_symbol(SETQ);
			push(car(p));
			push(p2);
			list(3);
			p2 = pop();
		###

		origPrintMode = printMode
		if passedPrintMode == PRINTMODE_FULL
			printMode = PRINTMODE_FULL
			accumulator = printline(p2);
			rememberPrint(accumulator, LAST_FULL_PRINT)
		else if passedPrintMode == PRINTMODE_PLAIN
			printMode = PRINTMODE_PLAIN
			accumulator = printline(p2);
			rememberPrint(accumulator, LAST_PLAIN_PRINT)
		else if passedPrintMode == PRINTMODE_2DASCII
			printMode = PRINTMODE_2DASCII
			accumulator = print2dascii(p2);
			rememberPrint(accumulator, LAST_2DASCII_PRINT)
		else if passedPrintMode == PRINTMODE_LATEX
			printMode = PRINTMODE_LATEX
			accumulator = printline(p2);
			rememberPrint(accumulator, LAST_LATEX_PRINT)
		else if passedPrintMode == PRINTMODE_LIST
			printMode = PRINTMODE_LIST
			accumulator = print_list(p2);
			rememberPrint(accumulator, LAST_LIST_PRINT)
		printMode = origPrintMode


		p = cdr(p);

	if DEBUG then console.log "emttedString from display: " + stringsEmittedByUserPrintouts
	return accumulator

rememberPrint = (theString, theTypeOfPrint) ->
	scan('"' + theString + '"')
	parsedString = pop()
	set_binding(symbol(theTypeOfPrint), parsedString)

print_str = (s) ->
	if DEBUG then console.log "emttedString from print_str: " + stringsEmittedByUserPrintouts
	return s

print_char = (c) ->
	return c

collectLatexStringFromReturnValue = (p) ->
	origPrintMode = printMode
	printMode = PRINTMODE_LATEX
	originalCodeGen = codeGen
	codeGen = false
	returnedString = print_expr(p)
	# some variables might contain underscores, escape those
	returnedString = returnedString.replace(/_/g, "\\\\_");
	printMode = origPrintMode
	codeGen = originalCodeGen
	if DEBUG then console.log "emttedString from collectLatexStringFromReturnValue: " + stringsEmittedByUserPrintouts
	return returnedString

printline = (p) ->
	accumulator = ""
	accumulator += print_expr(p)
	return accumulator


print_base_of_denom = (p1) ->
	accumulator = ""
	if (isfraction(p1) || car(p1) == symbol(ADD) || car(p1) == symbol(MULTIPLY) || car(p1) == symbol(POWER) || lessp(p1, zero)) # p1 is BASE
			accumulator += print_char('(')
			accumulator += print_expr(p1); # p1 is BASE
			accumulator += print_char(')')
	else
		accumulator += print_expr(p1); # p1 is BASE
	return accumulator

print_expo_of_denom = (p2) ->
	accumulator = ""
	if (isfraction(p2) || car(p2) == symbol(ADD) || car(p2) == symbol(MULTIPLY) || car(p2) == symbol(POWER)) # p2 is EXPO
		accumulator += print_char('(')
		accumulator += print_expr(p2); # p2 is EXPO
		accumulator += print_char(')')
	else
		accumulator += print_expr(p2); # p2 is EXPO
	return accumulator

# prints stuff after the divide symbol "/"

# d is the number of denominators

#define BASE p1
#define EXPO p2

print_denom = (p, d) ->
	accumulator = ""
	save()

	p1 = cadr(p); # p1 is BASE
	p2 = caddr(p); # p2 is EXPO

	# i.e. 1 / (2^(1/3))

	# get the cases like BASE^(-1) out of
	# the way, they just become 1/BASE
	if (isminusone(p2)) # p2 is EXPO
		accumulator += print_base_of_denom p1
		restore()
		return accumulator

	if (d == 1) # p2 is EXPO
		accumulator += print_char('(')

	# prepare the exponent
	# (needs to be negated)
	# before printing it out
	push(p2); # p2 is EXPO
	negate()
	p2 = pop(); # p2 is EXPO
	accumulator += print_power(p1,p2)
	if (d == 1)
		accumulator += print_char(')')
	restore()
	return accumulator


#define A p3
#define B p4

print_a_over_b = (p) ->
	accumulator = ""
	flag = 0
	n = 0
	d = 0

	save()

	# count numerators and denominators

	n = 0
	d = 0

	p1 = cdr(p)
	p2 = car(p1)

	if (isrational(p2))
		push(p2)
		mp_numerator()
		absval()
		p3 = pop(); # p3 is A
		push(p2)
		mp_denominator()
		p4 = pop(); # p4 is B
		if (!isplusone(p3)) # p3 is A
			n++
		if (!isplusone(p4)) # p4 is B
			d++
		p1 = cdr(p1)
	else
		p3 = one; # p3 is A
		p4 = one; # p4 is B

	while (iscons(p1))
		p2 = car(p1)
		if (is_denominator(p2))
			d++
		else
			n++
		p1 = cdr(p1)

	#debugger
	if printMode == PRINTMODE_LATEX
		accumulator += print_str('\\frac{')

	if (n == 0)
		accumulator += print_char('1')
	else
		flag = 0
		p1 = cdr(p)
		if (isrational(car(p1)))
			p1 = cdr(p1)
		if (!isplusone(p3)) # p3 is A
			accumulator += print_factor(p3); # p3 is A
			flag = 1
		while (iscons(p1))
			p2 = car(p1)
			if (is_denominator(p2))
				doNothing = 1
			else
				if (flag)
					accumulator += print_multiply_sign()
				accumulator += print_factor(p2)
				flag = 1
			p1 = cdr(p1)

	if printMode == PRINTMODE_LATEX
		accumulator += print_str('}{')
	else if printMode == PRINTMODE_PLAIN and !test_flag
		accumulator += print_str(" / ")
	else
		accumulator += print_str("/")

	if (d > 1 and printMode != PRINTMODE_LATEX)
		accumulator += print_char('(')


	flag = 0
	p1 = cdr(p)

	if (isrational(car(p1)))
		p1 = cdr(p1)

	if (!isplusone(p4)) # p4 is B
		accumulator += print_factor(p4); # p4 is B
		flag = 1

	while (iscons(p1))
		p2 = car(p1)
		if (is_denominator(p2))
			if (flag)
				accumulator += print_multiply_sign()
			accumulator += print_denom(p2, d)
			flag = 1
		p1 = cdr(p1)

	if (d > 1 and printMode != PRINTMODE_LATEX)
		accumulator += print_char(')')

	if printMode == PRINTMODE_LATEX
		accumulator += print_str('}')

	restore()
	return accumulator


print_expr = (p) ->
	accumulator = ""
	if (isadd(p))
		p = cdr(p)
		if (sign_of_term(car(p)) == '-')
			accumulator += print_str("-")
		accumulator += print_term(car(p))
		p = cdr(p)
		while (iscons(p))
			if (sign_of_term(car(p)) == '+')
				if printMode == PRINTMODE_PLAIN and !test_flag
					accumulator += print_str(" + ")
				else
					accumulator += print_str("+")
			else
				if printMode == PRINTMODE_PLAIN and !test_flag
					accumulator += print_str(" - ")
				else
					accumulator += print_str("-")
			accumulator += print_term(car(p))
			p = cdr(p)
	else
		if (sign_of_term(p) == '-')
			accumulator += print_str("-")
		accumulator += print_term(p)
	return accumulator

sign_of_term = (p) ->
	accumulator = ""
	if (car(p) == symbol(MULTIPLY) && isnum(cadr(p)) && lessp(cadr(p), zero))
		accumulator += '-'
	else if (isnum(p) && lessp(p, zero))
		accumulator += '-'
	else
		accumulator += '+'
	return accumulator

print_term = (p) ->
	accumulator = ""
	if (car(p) == symbol(MULTIPLY) && any_denominators(p))
		accumulator += print_a_over_b(p)
		return accumulator

	if (car(p) == symbol(MULTIPLY))
		p = cdr(p)

		# coeff -1?

		if (isminusone(car(p)))
			#			print_char('-')
			p = cdr(p)

		accumulator += print_factor(car(p))
		p = cdr(p)
		while (iscons(p))
			accumulator += print_multiply_sign()
			accumulator += print_factor(car(p))
			p = cdr(p)
	else
		accumulator += print_factor(p)
	return accumulator

print_subexpr = (p) ->
	accumulator = ""
	accumulator += print_char('(')
	accumulator += print_expr(p)
	accumulator += print_char(')')
	return accumulator

print_factorial_function = (p) ->
	accumulator = ""
	p = cadr(p)
	if (car(p) == symbol(ADD) || car(p) == symbol(MULTIPLY) || car(p) == symbol(POWER) || car(p) == symbol(FACTORIAL))
		accumulator += print_subexpr(p)
	else
		accumulator += print_expr(p)
	accumulator += print_char('!')
	return accumulator

print_ABS_latex = (p) ->
	accumulator = ""
	accumulator += print_str("\\left |")
	accumulator += print_expr(cadr(p))
	accumulator += print_str(" \\right |")
	return accumulator

print_BINOMIAL_latex = (p) ->
	accumulator = ""
	accumulator += print_str("\\binom{")
	accumulator += print_expr(cadr(p))
	accumulator += print_str("}{")
	accumulator += print_expr(caddr(p))
	accumulator += print_str("} ")
	return accumulator
	
print_DOT_latex = (p) ->
	accumulator = ""
	accumulator += print_expr(cadr(p))
	accumulator += print_str(" \\cdot ")
	accumulator += print_expr(caddr(p))
	return accumulator

print_SQRT_latex = (p) ->
	accumulator = ""
	accumulator += print_str("\\sqrt{")
	accumulator += print_expr(cadr(p))
	accumulator += print_str("} ")
	return accumulator
	
print_TRANSPOSE_latex = (p) ->
	accumulator = ""
	accumulator += print_str("{")
	if iscons(cadr(p))
		accumulator += print_str('(')
	accumulator += print_expr(cadr(p))
	if iscons(cadr(p))
		accumulator += print_str(')')
	accumulator += print_str("}")
	accumulator += print_str("^T")
	return accumulator

print_INV_latex = (p) ->
	accumulator = ""
	accumulator += print_str("{")
	if iscons(cadr(p))
		accumulator += print_str('(')
	accumulator += print_expr(cadr(p))
	if iscons(cadr(p))
		accumulator += print_str(')')
	accumulator += print_str("}")
	accumulator += print_str("^{-1}")
	return accumulator

print_DEFINT_latex = (p) ->
	accumulator = ""
	functionBody = car(cdr(p))

	p = cdr(p)
	originalIntegral = p
	numberOfIntegrals = 0

	while iscons(cdr(cdr(p)))
		numberOfIntegrals++
		theIntegral = cdr(cdr(p))

		accumulator += print_str("\\int^{")
		accumulator += print_expr(car(cdr(theIntegral)))
		accumulator += print_str("}_{")
		accumulator += print_expr(car(theIntegral))
		accumulator += print_str("} \\! ")
		p = cdr(theIntegral)

	accumulator += print_expr(functionBody)
	accumulator += print_str(" \\,")
	
	p = originalIntegral

	for i in [1..numberOfIntegrals]
		theVariable = cdr(p)
		accumulator += print_str(" \\mathrm{d} ")
		accumulator += print_expr(car(theVariable))
		if i < numberOfIntegrals
			accumulator += print_str(" \\, ")
		p = cdr(cdr(theVariable))
	return accumulator



print_tensor = (p) ->
	accumulator = ""
	accumulator += print_tensor_inner(p, 0, 0)[1]
	return accumulator

print_tensor_inner = (p, j, k) ->
	accumulator = ""
	i = 0
	if codeGen then accumulator += print_str("[") else accumulator += print_str('(')
	for i in [0...p.tensor.dim[j]]
		if (j + 1 == p.tensor.ndim)
			accumulator += print_expr(p.tensor.elem[k])
			k++
		else
			[k, retString] = print_tensor_inner(p, j + 1, k)
			accumulator += retString
		if (i + 1 < p.tensor.dim[j])
			accumulator += print_str(",")
	if codeGen then accumulator += print_str("]") else accumulator += print_str(')')
	return [k, accumulator]

print_base = (p) ->
	accumulator = ""
	if (isadd(cadr(p)) || caadr(p) == symbol(MULTIPLY) || caadr(p) == symbol(POWER) || isnegativenumber(cadr(p)))
		accumulator += print_str('(')
		accumulator += print_expr(cadr(p))
		accumulator += print_str(')')
	else if (isnum(cadr(p)) && (lessp(cadr(p), zero) || isfraction(cadr(p))))
		accumulator += print_str('(')
		accumulator += print_factor(cadr(p))
		accumulator += print_str(')')
	else
		accumulator += print_factor(cadr(p))
	return accumulator

print_exponent = (p) ->
	accumulator = ""
	if (iscons(caddr(p)) || isfraction(caddr(p)) || (isnum(caddr(p)) && lessp(caddr(p), zero)))
		accumulator += print_str('(')
		accumulator += print_expr(caddr(p))
		accumulator += print_str(')')
	else
		accumulator += print_factor(caddr(p))
	return accumulator

print_power = (base, exponent) ->
	accumulator = ""

	#debugger

	if codeGen
		accumulator += print_str("Math.pow(")
		accumulator += print_base_of_denom base
		accumulator += print_str(", ")
		accumulator += print_expo_of_denom exponent
		accumulator += print_str(')')
		return accumulator

	if ((equaln(get_binding(symbol(PRINT_LEAVE_E_ALONE)), 1)) and base == symbol(E))
		if printMode == PRINTMODE_LATEX
			accumulator += print_str("e^{")
			accumulator += print_expr(exponent)
			accumulator += print_str("}")
		else
			accumulator += print_str("exp(")
			accumulator += print_expr(exponent)
			accumulator += print_str(')')
		return accumulator

	
	if ((equaln(get_binding(symbol(PRINT_LEAVE_X_ALONE)), 0)) or base.printname != "x")
		# if the exponent is negative then
		# we invert the base BUT we don't do
		# that if the base is "e", because for
		# example when trigonometric functions are
		# expressed in terms of exponential functions
		# that would be really confusing, one wants to
		# keep "e" as the base and the negative exponent
		if (base != symbol(E))
			if (isminusone(exponent))
				if printMode == PRINTMODE_LATEX
					accumulator += print_str("\\frac{1}{")
				else if printMode == PRINTMODE_PLAIN and !test_flag
					accumulator += print_str("1 / ")
				else
					accumulator += print_str("1/")

				if (iscons(base) and printMode != PRINTMODE_LATEX)
					accumulator += print_str('(')
					accumulator += print_expr(base)
					accumulator += print_str(')')
				else
					accumulator += print_expr(base)

				if printMode == PRINTMODE_LATEX
					accumulator += print_str("}")

				return accumulator

			if (isnegativeterm(exponent))
				if printMode == PRINTMODE_LATEX
					accumulator += print_str("\\frac{1}{")
				else if printMode == PRINTMODE_PLAIN and !test_flag
					accumulator += print_str("1 / ")
				else
					accumulator += print_str("1/")

				push(exponent)
				push_integer(-1)
				multiply()
				newExponent = pop()

				if (iscons(base) and printMode != PRINTMODE_LATEX)
					accumulator += print_str('(')
					accumulator += print_power(base, newExponent)
					accumulator += print_str(')')
				else
					accumulator += print_power(base, newExponent)


				if printMode == PRINTMODE_LATEX
					accumulator += print_str("}")

				return accumulator


		if (isfraction(exponent) and printMode == PRINTMODE_LATEX)
				accumulator += print_str("\\sqrt")
				push(exponent)
				denominator()
				denomExponent = pop()
				# we omit the "2" on the radical
				if !isplustwo(denomExponent)
					accumulator += print_str("[")
					accumulator += print_expr(denomExponent)
					accumulator += print_str("]")
				accumulator += print_str("{")
				push(exponent)
				numerator()
				numExponent = pop()
				exponent = numExponent
				accumulator += print_power(base, exponent)
				accumulator += print_str("}")
				return accumulator

	if printMode == PRINTMODE_LATEX and isplusone(exponent)
		# if we are in latex mode we turn many
		# radicals into a radix sign with a power
		# underneath, and the power is often one
		# (e.g. square root turns into a radical
		# with a power one underneath) so handle
		# this case simply here, just print the base
		accumulator += print_expr(base)
	else
		# print the base,
		# determining if it needs to be
		# wrapped in parentheses or not
		if (isadd(base) || isnegativenumber(base))
			accumulator += print_str('(')
			accumulator += print_expr(base)
			accumulator += print_str(')')
		else if ( car(base) == symbol(MULTIPLY) || car(base) == symbol(POWER))
			if printMode != PRINTMODE_LATEX then accumulator += print_str('(')
			accumulator += print_factor(base, true)
			if printMode != PRINTMODE_LATEX then accumulator += print_str(')')
		else if (isnum(base) && (lessp(base, zero) || isfraction(base)))
			accumulator += print_str('(')
			accumulator += print_factor(base)
			accumulator += print_str(')')
		else
			accumulator += print_factor(base)

		# print the power symbol
		#debugger
		if printMode == PRINTMODE_PLAIN and !test_flag
			#print_str(" ^ ")
			accumulator += print_str(power_str)
		else
			accumulator += print_str("^")

		# print the exponent
		if printMode == PRINTMODE_LATEX
			# in latex mode, one can omit the curly braces
			# wrapping the exponent if the exponent is only
			# one character long
			if print_expr(exponent).length > 1
				accumulator += print_str("{")
				accumulator += print_expr(exponent)
				accumulator += print_str("}")
			else
				accumulator += print_expr(exponent)
		else if (iscons(exponent) || isfraction(exponent) || (isnum(exponent) && lessp(exponent, zero)))
			accumulator += print_str('(')
			accumulator += print_expr(exponent)
			accumulator += print_str(')')
		else
			accumulator += print_factor(exponent)
	return accumulator

print_index_function = (p) ->
	accumulator = ""
	p = cdr(p);
	if (caar(p) == symbol(ADD) || caar(p) == symbol(MULTIPLY) || caar(p) == symbol(POWER) || caar(p) == symbol(FACTORIAL))
		accumulator += print_subexpr(car(p));
	else
		accumulator += print_expr(car(p));
	accumulator += print_str('[');
	p = cdr(p);
	if (iscons(p))
		accumulator += print_expr(car(p));
		p = cdr(p);
		while(iscons(p))
			accumulator += print_str(',');
			accumulator += print_expr(car(p));
			p = cdr(p);
	accumulator += print_str(']');
	return accumulator


print_factor = (p, omitParens) ->
	accumulator = ""
	if (isnum(p))
		accumulator += print_number(p, false)
		return accumulator

	if (isstr(p))
		accumulator += print_str("\"")
		accumulator += print_str(p.str)
		accumulator += print_str("\"")
		return accumulator

	if (istensor(p))
		accumulator += print_tensor(p)
		return accumulator

	if (car(p) == symbol(MULTIPLY))
		if !omitParens
			if (sign_of_term(p) == '-' or printMode != PRINTMODE_LATEX)
				if printMode == PRINTMODE_LATEX
					accumulator += print_str(" \\left (")
				else
					accumulator += print_str('(')
		accumulator += print_expr(p)
		if !omitParens
			if (sign_of_term(p) == '-' or printMode != PRINTMODE_LATEX)
				if printMode == PRINTMODE_LATEX
					accumulator += print_str(" \\right ) ")
				else
					accumulator += print_str(')')
		return accumulator
	else if (isadd(p))
		if !omitParens then accumulator += print_str('(')
		accumulator += print_expr(p)
		if !omitParens then accumulator += print_str(')')
		return accumulator

	if (car(p) == symbol(POWER))
		base = cadr(p)
		exponent = caddr(p)
		accumulator += print_power(base, exponent)
		return accumulator

	#	if (car(p) == _list) {
	#		print_str("{")
	#		p = cdr(p)
	#		if (iscons(p)) {
	#			print_expr(car(p))
	#			p = cdr(p)
	#		}
	#		while (iscons(p)) {
	#			print_str(",")
	#			print_expr(car(p))
	#			p = cdr(p)
	#		}
	#		print_str("}")
	#		return
	#	}

	if (car(p) == symbol(FUNCTION))
		fbody = cadr(p)
		
		if !codeGen
			parameters = caddr(p)
			accumulator += print_str "function "
			if DEBUG then console.log "emittedString from print_factor " + stringsEmittedByUserPrintouts
			returned = print_list parameters
			accumulator += returned
			accumulator += print_str " -> "
		accumulator += print_expr fbody
		return accumulator

	if (car(p) == symbol(PATTERN))

		accumulator += print_expr(caadr(p))
		if printMode == PRINTMODE_LATEX
			accumulator += print_str(" \\rightarrow ")
		else
			if printMode == PRINTMODE_PLAIN and !test_flag
				accumulator += print_str(" -> ")
			else
				accumulator += print_str("->")

		accumulator += print_expr car(cdr(cadr(p)))
		return accumulator


	if (car(p) == symbol(INDEX) && issymbol(cadr(p)))
		accumulator += print_index_function(p)
		return accumulator

	if (car(p) == symbol(FACTORIAL))
		accumulator += print_factorial_function(p)
		return accumulator
	else if (car(p) == symbol(ABS) && printMode == PRINTMODE_LATEX)
		accumulator += print_ABS_latex(p)
		return accumulator
	else if (car(p) == symbol(SQRT) && printMode == PRINTMODE_LATEX)
		#debugger
		accumulator += print_SQRT_latex(p)
		return accumulator
	else if (car(p) == symbol(TRANSPOSE) && printMode == PRINTMODE_LATEX)
		accumulator += print_TRANSPOSE_latex(p)
		return accumulator
	else if (car(p) == symbol(INV) && printMode == PRINTMODE_LATEX)
		accumulator += print_INV_latex(p)
		return accumulator
	else if (car(p) == symbol(BINOMIAL) && printMode == PRINTMODE_LATEX)
		accumulator += print_BINOMIAL_latex(p)
		return accumulator
	else if (car(p) == symbol(DEFINT) && printMode == PRINTMODE_LATEX)
		accumulator += print_DEFINT_latex(p)
		return accumulator
	else if (isinnerordot(p) && printMode == PRINTMODE_LATEX)
		accumulator += print_DOT_latex(p)
		return accumulator


	if (iscons(p))
		#if (car(p) == symbol(FORMAL) && cadr(p)->k == SYM) {
		#	print_str(((struct symbol *) cadr(p))->name)
		#	return
		#}
		accumulator += print_factor(car(p))
		p = cdr(p)
		if !omitParens then accumulator += print_str('(')
		if (iscons(p))
			accumulator += print_expr(car(p))
			p = cdr(p)
			while (iscons(p))
				accumulator += print_str(",")
				accumulator += print_expr(car(p))
				p = cdr(p)
		if !omitParens then accumulator += print_str(')')
		return accumulator

	if (p == symbol(DERIVATIVE))
		accumulator += print_char('d')
	else if (p == symbol(E))
		if printMode == PRINTMODE_LATEX
			accumulator += print_str("e")
		else
			accumulator += print_str("exp(1)")
	else if (p == symbol(PI))
		if printMode == PRINTMODE_LATEX
			accumulator += print_str("\\pi")
		else
			accumulator += print_str("pi")
	else
		accumulator += print_str(get_printname(p))
	return accumulator


print_list = (p) ->
	accumulator = ""
	switch (p.k)
		when CONS
			accumulator += ('(')
			accumulator += print_list(car(p))
			if p == cdr(p) and p != symbol(NIL)
				console.log "oh no recursive!"
				debugger
			p = cdr(p)
			while (iscons(p))
				accumulator += (" ")
				accumulator += print_list(car(p))
				p = cdr(p)
				if p == cdr(p) and p != symbol(NIL)
					console.log "oh no recursive!"
					debugger
			if (p != symbol(NIL))
				accumulator += (" . ")
				accumulator += print_list(p)
			accumulator += (')')
		when STR
			#print_str("\"")
			accumulator += (p.str)
			#print_str("\"")
		when NUM, DOUBLE
			accumulator += print_number(p, true)
		when SYM
			accumulator += get_printname(p)
		else
			accumulator += ("<tensor>")
	return accumulator

print_multiply_sign = ->
	accumulator = ""
	if printMode == PRINTMODE_LATEX
		if printMode == PRINTMODE_PLAIN and !test_flag
			accumulator += print_str(" ")
		else
			return accumulator

	if printMode == PRINTMODE_PLAIN and !test_flag and !codeGen
		accumulator += print_str(" ")
	else
		accumulator += print_str("*")
	return accumulator

is_denominator = (p) ->
	if (car(p) == symbol(POWER) && cadr(p) != symbol(E) && isnegativeterm(caddr(p)))
		return 1
	else
		return 0

# don't consider the leading fraction
# we want 2/3*a*b*c instead of 2*a*b*c/3

any_denominators = (p) ->
	p = cdr(p)
	#	if (isfraction(car(p)))
	#		return 1
	while (iscons(p))
		q = car(p)
		if (is_denominator(q))
			return 1
		p = cdr(p)
	return 0

