top_estack Variable (ROM Call 0x109)

args.h, estack.h

ESI top_estack;

Points to the top of the expression stack.

The global variable top_estack points to the top (i.e. the last byte) of the expression stack. Strictly speaking, in "nostub" mode it is not a real variable but smart macro, although it works like it is a variable. The expression stack is the place in the memory where TI keeps expressions during evaluation. All statements are tokenized before being executed (interpreted). Instructions are reduced to (byte sized) quanta and parsed into Reverse Polish Notation (RPN). This is a common technique in interpreted languages. Expressions, functions, etc. are all stored in RPN form, to allow for efficient operation of the expressions stack. See below for more details about organization of the expression stack.

The actual processing of all expressions is done via the expression stack. The position in the stack is given by top_estack. Pushing a value appends it to the expression stack and increments top_estack. When a expression is interpreted, expressions are reduced, and executed as far as possible. Whatever remains on the stack is the result, this may then be stored or processed later.

When a file is interpreted the end of the variable is found and it is processed as a separate expression stack. It is then processed recursively, producing a simplified version on the real expression stack. Expressions are therefore interpreted from the top (high memory) recursively.

As an artefact of expressions processing mechanism, the arguments of the called program are kept also on the expression stack. It grows upwards, and the last argument is stored first. After the assembly program is called, the image of the expression stack is as follows:

Each string entry on the expression stack is stored as follows (from lower to higher addresses): Each integer entry is stored as follows: Each fraction entry is stored as follows: Each floating point entry is stored as follows: If the entry is complex number, real part is stored first (which can be integer, float, fraction, etc.), then imaginary part. COMPLEX_TAG (0x9D) is stored after them, so if the current argument type is complex, decrease the argument pointer by one, then first read imaginary part, then real part separately.

If the entry is composite (i.e. if it is a list or a matrix), the first byte is end_of_list marker (byte END_TAG or 0xE5), then follow each element of the list in reverse order (starting from the last element), and the last byte is LIST_TAG (0xD9). Now, you surely have an idea how you can pick up elements from the list. Note that a matrix is a "list of lists".

Signed zeros (POSITIVE_ZERO and NEGATIVE_ZERO) are represented as fractions +0/1 and -0/1.

Variable names are stored exactly like strings without terminating STR_TAG (i.e. it is a sequence of letters bounded with two zero bytes), so "variable" tag is just a zero byte. There is an exception: one-letter variables have unique one-byte tags (see Tags for more info. Also, note that variable names are always stored with lowercase letters. Variables whose names ends with an underscore are assumed to be complex, and variables whose names starts with an underscore are assumed to represent physical units.

Expressions are stored in RPN (Reverse Polish Notation) form (also known as postfix form). So, function calls like func(arg1,arg2,...argn) are stored as sequence

argn ... arg2 arg1 func_tag

and terms like arg1 operator arg2 are stored as arg1 arg2 operator_tag or arg2 arg1 operator_tag, depending on the concrete operator. The situation is analogous for unary operators. Note that a "pointer to an expression" is a pointer to the last byte of the expression! When a function (or operator) has variable number of arguments, END_TAG is used to indicate "no more arguments". See Tags for complete list of various tags. This will be illustrated with some examples:

Algebraic form: integrate (e^(x^2), x, 1, 2)
RPN form: 2 1 x 2 x ^ e ^ integrate
Sequence of bytes:    [02 01 1F] [01 01 1F] [08] [02 01 1F] [08] [93] [25] [93] [C4]

Algebraic form: sum (sqrt (1 + x), x, 0, a)
RPN form: a 0 x x 1 sqrt sum
Sequence of bytes:    [0B] [00 1F] [08] [08] [01 01 1F] [8B] [51]

Algebraic form: a + b + a - b + (a + b) * (a - b) -> a
RPN form: a b + a + b - a b + a b - * + a ->
Sequence of bytes:    [0B] [0C] [8B] [0B] [8B] [0C] [8D] [0B] [0C] [8B] [0B] [0C] [8D] [8F] [8B] [0B] [80]

Algebraic form: {{1, 2}, {3, 4}}
RPN form: END_TAG END_TAG 4 3 LIST_TAG END_TAG 2 1 LIST_TAG LIST_TAG
Sequence of bytes:    [E5] [E5] [04 01 1F] [03 01 1F] [D9] [E5] [02 01 1F] [01 01 1F] [D9] [D9]

Algebraic form: my_func (a, b, c)
RPN form: END_TAG c b a my_func USERFUNC_TAG
Sequence of bytes:    [E5] [0D] [0C] [0B] [00 6D 79 5F 66 75 6E 63 00] [DA]

To perform some algebraic transformations on more unique way, expressions should be transformed into an equivalent form called "internal canonic form". In such form, for example, all constants are always in front of variables, e.g. 'x*3' and 'x+3' becomes '3*x' and '3+x' (although the second example will be printed as 'x+3'). Also, expressions like 'x/y' or 'x-y' in internal canonic form do not contain subtractions and divisions. As the parameter list (when the program is called from TI-Basic) is always in internal canonic form, such expressions will never be observed as-is in parameter lists etc. because they will be converted before passing them to the program. A lot of functions for algebraic manipulations automatically convert the expression in the internal canonic form, but when this is not true, you can always force the conversion using explicit call to push_internal_simplify function. Note that the reverse conversion (i.e. back from the canonic form into a regular form) is performed anytime when you try to print out the expression. Here is the list of the most common transformations which appears during the transformation into the internal canonic form:

ExpressionStandard canonic form
-x(-1)*x
x-yx+y*(-1)
x/yx*y^(-1)
e^xexp(x)
x^yexp(ln(x)*y)
[ except when "y" is an integer or a fraction ]
eexp(1)
sqrt(x)x^(1/2)
log(x)ln(x)*(ln(10)^(-1))
sin(x)trig(x,0)
[ assuming "radian" mode; for "trig" function, see SINCOS_TAG ]
cos(x)trig(x,1)
tan(x)trig(x,0)*trig(x,1)^(-1)
sinh(x)exp(x)*(1/2)+exp(x)^(-1)*(-1/2)
cosh(x)exp(x)*(1/2)+exp(x)^(-1)*(1/2)
tanh(x)(exp(x)^2+1)^(-1)*(exp(x)^2+(-1))
x xor y(not x and y) or (x and not y)

Mode dependent calculations are performed by converting expressions to a specific format, i.e. for trigonometric functions all values are converted to radians before passing them to radian trigonometric functions.

A variable may consist of multiple expressions, these are separated by several special quanta: NEXTEXPR_TAG and NEWLINE_TAG. The last expression is marked with ENDSTACK_TAG. See MULTI_EXPR.

If everything mentioned above is not so clear for you, compile and run the following example (called "Print EStack"):
// Print bottom_estack and top_estack

#define USE_TI89              // Compile for TI-89
#define USE_TI92PLUS          // Compile for TI-92 Plus
#define USE_V200              // Compile for V200

#define MIN_AMS 100           // Compile for AMS 1.00 or higher
#define SAVE_SCREEN           // Save/Restore LCD Contents

#include <tigcclib.h>         // Include All Header Files

// Main Function
void _main(void)
{
  ClrScr ();
  printf_xy (0, 40, "Bottom = 0x%lp", bottom_estack);
  printf_xy (0, 50, "Top = 0x%lp", top_estack);
  ngetchx ();
}
Run this program in VTI and pass to it parameters as you want. top_estack will be shown on the screen. During waiting for a keypress, enter the debugger and look at the addresses shown, to see how parameters are stored.


Used by: can_be_approxed, check_estack_size, compare_complex_magnitudes, delete_between, deleted_between, did_push_cnvrt_Float_to_integer, index_below_display_expression_aux, is_antisymmetric, is_symmetric, map_tail, map_tail_Int, next_expression_index, NG_graphESI, Parse2DExpr, Parse2DMultiExpr, push_between, push_expr_quantum, push_expr2_quantum, push_Float, push_Float_to_nonneg_int, push_Float_to_rat, push_internal_simplify, push_offset_array, push_parse_text, push_quantum, push_quantum_pair, push_round_Float, push_transpose_aux, push_ushort_to_integer, reset_estack_size, should_and_did_push_approx_arg2, TokenizeSymName, HeapAllocESTACK, ArgCount, EX_getArg, InitArgPtr, cmd_blddata, cmd_circle, cmd_custom, cmd_dialog, cmd_disp, cmd_drawfunc, cmd_drawinv, cmd_drawparm, cmd_drawpol, cmd_endfor, cmd_endwhile, cmd_fill, cmd_for, cmd_get, cmd_if, cmd_ifthen, cmd_input, cmd_inputstr, cmd_linetan, cmd_local, cmd_newdata, cmd_newplot, cmd_output, cmd_passerr, cmd_pause, cmd_popup, cmd_prompt, cmd_randseed, cmd_request, cmd_shade, cmd_sinreg, cmd_slpline, cmd_sorta, cmd_sortd, cmd_toolbar, cmd_try, cmd_while, did_push_anti_deriv, did_push_series, push_1st_derivative, push_abs, push_acos, push_acosh, push_asin, push_asinh, push_atan, push_atanh, push_ceiling, push_coldim, push_colnorm, push_comb, push_comdenom, push_conj, push_cosh, push_cross_product, push_csolve, push_cumsum, push_czeros, push_def_int, push_denominator, push_desolve, push_determinant, push_diag, push_dimension, push_dotproduct, push_eigvc, push_eigvl, push_exp, push_expand, push_extended_prod, push_factor, push_floor, push_fractional_part, push_gcd_numbers, push_im, push_integer_lcm, push_integer_part, push_integer_quotient, push_integer_remainder, push_is_prime, push_left, push_lim, push_list_to_mat, push_ln, push_log10, push_matnorm, push_max, push_max1, push_max2, push_mean, push_median, push_mid, push_min, push_min1, push_min2, push_mod, push_mrowadd, push_nint, push_nsolve, push_nth_derivative, push_numerator, push_part, push_perm, push_phase, push_pttest, push_pxltest, push_r_cis, push_rand, push_randmat, push_randnorm, push_randpoly, push_re, push_rec_to_angle, push_red_row_ech, push_right, push_rotate, push_round, push_row_echelon, push_rowadd, push_rowdim, push_rownorm, push_rowswap, push_sequence, push_shift, push_sign, push_simult, push_sin2, push_sinh, push_solve, push_stddev, push_str_to_expr, push_string, push_submat, push_summation, push_switch, push_tan, push_tanh, push_unitv, push_variance, push_when, push_zeros, did_push_to_polar, push_and, push_assignment, push_degrees, push_dot_exponentiate, push_equals, push_exponentiate, push_factorial, push_greater_than, push_greater_than_or_equals, push_indir_name, push_less_than, push_less_than_or_equals, push_list_plus, push_list_times, push_matrix_product, push_negate, push_not, push_not_equals, push_or, push_product, push_radians, push_ratio, push_substitute_no_simplify, push_substitute_simplify, push_substitute_using_such_that, push_sum, push_to_cylin, push_to_sphere, VarNew, VarOpen, VarSaveAs, EV_defaultHandler, handleRclKey, handleVarLinkKey, GR3_paint3d, GR3_xyToWindow, HomeExecute, HomePushEStack, HS_popEStack, getcalc, OSLinkCmd, sendcalc, atof, add_to_top, and_onto_top, are_units_consistent, compare_numbers, cpt_gr_fun, cpt_gr_param, cpt_gr_polar, de_initRes, de_loop, did_map_aggregate_arg, did_push_approx_inflection_point, did_push_divide_units, did_push_lincf, divide_top, dv_create_graph_titles, EQU_getNameInfo, ForceFloat, get_lb, get_list_indices, get_matrix_indices, get_ub, GetStatValue, GM_Derivative, GM_DistArc, GM_Inflection, GM_Integrate, GM_Intersect, GM_Math1, GM_TanLine, gr_ck_solvergraph, gr_execute_de, gr_execute_seq, GR_Pan, GR3_addContours, GraphOrTableCmd, GT_CalcDepVals, GT_PrintCursor, has_different_variable, index_if_pushed_binomial_info, index_if_pushed_qquad_info, InitDEMem, InitTimeSeq, is_equivalent_to, is_negative, is_never0, is_nonnegative, is_nonpositive, is_positive, is_real, is_term_improper, or_onto_top, push_auto_units_conversion, push_but_factor, push_but_term, push_constant_factors, push_constant_terms, push_dependent_factors, push_dependent_terms, push_div_dif_1c, push_div_dif_1f, push_float_qr_fact, push_format, push_gcd_then_cofactors, push_independent_factors, push_independent_terms, push_lu_fact, push_make_proper, push_minus_recip_of_quantum, push_mrow_aux, push_negate_quantum_as_negint, push_nonconstant_factors, push_nonconstant_terms, push_nonnumeric_factors, push_parse_prgm_or_func_text, push_pi_on_quantum, push_poly_deg_in_var_or_kernel, push_poly_qr, push_quantum_as_nonnegative_int, push_quantum_pair_as_pos_frac, push_reciprocal, push_reciprocal_of_quantum, push_simplify, push_simplify_statements, push_sq_matrix_to_whole_number, push_standardize, push_symbolic_qr_fact, push_trig, push_user_func, push_var, push_zero_partial_column, raise_to_top, Regraph, replace_top_with_post_simplified, replace_top_with_reciprocal, replace_top2_with_and, replace_top2_with_imre, replace_top2_with_or, replace_top2_with_pow, replace_top2_with_prod, replace_top2_with_ratio, replace_top2_with_sum, run_one_seq, seqWebInit, setup_unit_system, SP_Define, spike_geo_titles, spike_in_editor, spike_optionD, spike_titles_in_editor, store_func_def, store_to_subscripted_element, subtract_from_top, time_loop, times_top, tokenize_if_TI_92_or_text, TokenizeName, VarStoreLink, FolderDel, FolderRename, HSymDel, SymFindFolderName, VarRecall, ROM Call 0x45B, ROM Call 0x468, ROM Call 0x46F, ROM Call 0x47F, ROM Call 0x480, ROM Call 0x484, ROM Call 0x485, ROM Call 0x48D, ROM Call 0x494, ROM Call 0x495, ROM Call 0x4C2, ROM Call 0x4C6, ROM Call 0x4C7, ROM Call 0x4D1, ROM Call 0x4E6, ROM Call 0x4EC, ROM Call 0x4ED, ROM Call 0x4F2, ROM Call 0x5F1, ROM Call 0x606


See also: bottom_estack