The <args.h> header file


  
This header file contains the following functions:
ArgCount           EX_getArg              EX_getBCD          GetArgType
GetFloatArg        GetIntArg              GetStrnArg         GetSymstrArg
InitArgPtr         RemainingArgCnt        SkipArg
the following global variables:
top_estack
and the following predefined types:
bcd                Bool                   ESI                Tags
ti_float
NOTE: The header file estack.h contains much more powerful set of functions for manipulating with expressions stack.

Functions


unsigned short ArgCount (void);

Returns a number of arguments passed to the called program.

ArgCount returns a number of arguments passed to the called program. It is a simple macro which calls TIOS function remaining_element_count. See also RemainingArgCnt.

void InitArgPtr (ESI &ap);

Initializes a pointer to the first argument passed to the called program.

InitArgPtr is a macro which initializes ap (which is a pointer of type ESI) to point to the first argument passed to the assembly program. Principally, calling
InitArgPtr (argptr);
is equal to doing
argptr = top_estack;
See top_estack for more info.

InitArgPtr must be used before the first call to GetStrnArg etc. Here is an example of the program which reads string or integer arguments passed to it, and displays them on the screen, one by one:
#include <tigcclib.h>
int _ti89;
void _main(void)
{
   ESI argptr;
   int argtype;
   long num;
   InitArgPtr (argptr);
   while ((argtype = GetArgType(argptr)) != END_TAG)
      {
         DrawStr(0, 30, "              ", A_REPLACE);
         if (argtype == STR_TAG)
            DrawStr (0, 30, GetStrnArg (argptr), A_REPLACE);
         else if (argtype == POSINT_TAG || argtype == NEGINT_TAG)
            {
               num = GetIntArg (argptr);
               if (argtype == NEGINT_TAG) num = -num;
               printf_xy (0, 30, "%ld", num);
            }
         else
            {
               DrawStr (0, 30, "Wrong arg type!", A_REPLACE);
               ngetchx ();
               break;
            }
         ngetchx ();
      }
}
If the name of this program is example.89z, try to call it on TI using
example ("strarg1", 123, -12, "strarg2")
to see how it works in practice.

NOTE: I used notation "&ap" in the prototype description, although passing by reference does not exist in ordinary C (only in C++). However, this macro is implemented on such way that it simulates "passing by reference".

unsigned char GetArgType (ESI ap);

Returns the type of the current argument.

GetArgType returns an one-byte value which determines the type of the current argument (pointed to by ap). There are so many types of arguments: strings, integers (positive or negative), fractions, floats, symbols, various algebraic expressions, lists, matrices, etc. Enum Tags defines a lot of constants: the most commonly used in argument lists are STR_TAG, POSINT_TAG, NEGINT_TAG, FLOAT_TAG, POSFRAC_TAG, ENDFRAC_TAG, COMPLEX_TAG, LIST_TAG and END_TAG. They represents respectively a string, a positive integer, a negative integer, a floating point value, a positive fraction, a negative fraction, a complex number, a begining of the list structure and an end-of-list marker (which also has meaning "no more arguments"). Any values except these need to be regarded as "an expression": you need to handle them "by hand" (of course, if you know how). See InitArgPtr for an example of usage.

NOTE: You can use SkipArg to bypass the argument which you don't know how to handle (or, which you don't want to handle for any reason).

void SkipArg (ESI &ap);

Skips the current argument.

SkipArg is a macro which modifies ap to point to the next argument in the argument list, regardless of its type. Note that this function must not be called if GetArgType returns END_TAG, i.e. if there is no more arguments. Else, an error will be thrown.

NOTE: SkipArg is implemented by calling TIOS function next_expression_index.

char *GetStrnArg (ESI &ap);

Returns the current argument of string type.

GetStrnArg is a macro which returns the current string argument (pointed to by ap) and modifies ap to point to the next argument in the argument list. So, each successive time GetStrnArg is used, it returns the next argument in the argument list. See InitArgPtr for an example of usage. Note that GetStrnArg assumes that the current argument IS a string (this may be checked using GetArgType). If this is not true, the result of GetStrnArg is unpredictable.

unsigned long GetIntArg (ESI &ap);

Returns the current argument of integer type.

GetIntArg is a macro which returns the current integer argument (pointed to by ap) and modifies ap to point to the next argument in the argument list. So, each successive time GetIntArg is used, it returns the next argument in the argument list. If the argument is a negative number (check the sign using GetArgType), GetIntArg returns its absolute value. See InitArgPtr for an example of usage. Note that GetIntArg assumes that the current argument IS an integer, either positive or negative (this may be checked using GetArgType). If this is not true, the result of GetIntArg is unpredictable.

If the current argument type is a fraction, do the following to pick it:
numerator = GetIntArg (ap);
ap++;
denominator = GetIntArg (ap);
i.e. pick two integers, with increasing argument pointer between two picks.

NOTE: It is not recommended to do something like
a = GetIntArg (top_estack);
It works fine sometimes, but not always. GetIntArg is a function-looking macro, with changes the value of its actual argument. So, if you write the statement mentioned above, you will also change the value of TIOS system variable top_estack, which is not always a good idea. So, I strictly recommend using an auxilary variable, like in the following example:
ESI argptr = top_estack;
...
a = GetIntArg (argptr);
Using this method, you will avoid unexpected changes of top_estack.

float GetFloatArg (ESI &ap);

Returns the current argument of floating point type.

GetFloatArg is a macro which returns the current floating point argument (pointed to by ap) and modifies ap to point to the next argument in the argument list. So, each successive time GetFloatArg is used, it returns the next argument in the argument list. Note that GetFloatArg assumes that the current argument IS a floating point value (not an integer). This may be checked using GetArgType. If this is not true, the result of GetFloatArg is unpredictable. For more flexibility, see also estack_number_to_Float from estack.h header file.

char *GetSymstrArg (ESI &ap);

Returns a pointer to the terminating zero byte of the current argument of string type.

GetSymstrArg does the same task as GetStrnArg but returns a pointer to the terminating zero byte of the string, instead of a pointer to the first byte of the string. This function is implemented because nearly all functions for TIOS VAT handling need just the pointer to the terminating byte of the string. As the arguments are stored in memory as strings which are bounded with zero bytes from both sides, the result of GetSymstrArg may be directly passed to TIOS VAT routines. See vat.h for more info.

unsigned short RemainingArgCnt (ESI ap);

Returns a remaining number of arguments passed to the called program.

RemainingArgCnt returns a number of remaining arguments passed to the called program, i.e. a number of arguments which are not yet picked up. It is a simple macro which calls TIOS function remaining_element_count. See also ArgCount.

ESI EX_getArg (short n);

Returns a pointer to the n-th argument.

EX_getArg is TIOS function which may be useful if you want to access arguments in non_sequential order. EX_getArg returns a pointer to the argument which ordinal number is n (which may be later processed using GetIntArg etc.). Arguments are numbered from zero (i.e. 0, 1, 2, ... N-1 where N is the total number of arguments). Note that when n = N, EX_getArg returns NULL, and when n > N, EX_getArg throws an error, so it is good idea to check in advance the total number of arguments using ArgCount.

short EX_getBCD (short n, float *dest);

Gets the n-th floating point argument.

EX_getBCD is a somewhat limited TIOS function. It first calls EX_getArg passing n to it. Then, if the argument pointed to by the result of EX_getArg is not a floating point number, EX_getBCD returns FALSE, else stores the floating point value to the variable pointed to by dest and returns TRUE.


Global variables

ESI top_estack;

The global variable top_estack points to the top (i.e. the last byte) of the expressions stack. Strictly speaking, in "nostub" mode it is not a real variable but smart macro, although it works like it is a variable. Expressions stack is the place in the memory where TI keeps expressions during the evaluation. All statements are tokenised 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 languagues. 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 expressions stack.

The actual processing of all expressions is done via the expressions stack. The position in the stack is given by top_estack. Pushing a value appends it to the expressions 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 expressions stack. Expressions are therefore interpreted from the top (high memory) recursively.

As an artefact of expressions processing mechhanism, the arguments of the called program are kept also on the expressions stack. It grows upwards, and the last argument is stored first. After the assembly program is called, the image of the expressions stack is as follows: Each string entry on the expressions 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 understore 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 of 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 ilustrated with some examples:

Algebraic form: integrate (e^(x^2), x, 1, 2)
RPN form: 2 1 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 substractions 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 explicite 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 canonnic 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.

If everything mentioned above is not so clear for you, compile and run the following program:
#include <tigcclib.h>
int _ti89;
void _main(void)
{
  printf_xy (0, 50, "Top=%lx", 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 the addresses below shown address, to see how parameters are stored.


Predefined types


type ESI

ESI is "expressions stack index" which is, in fact, the pointer to the tag byte on the TIOS expressions stack. It is defined as
typedef char *ESI;
See top_estack and Tags for more info about the expressions stack.

enum Bool

Bool is enumerated type for describing true or false values. It is defined as
enum Bool {FALSE, TRUE};

enum Tags

Tags is enumerated type for describing types of entries on the expressions stack. This enum is very big, as there is a lot of various entries (see top_estack for more info about how entries on the expressions stack are organized). The complete list of tags with their meanings is given in the documentation for estack.h header file (click here to see the list).

type ti_float

Starting for TIGCC 0.9, ti_float is an alias name for standard ANSI float type, introduced to keep backward compatibility with previous releases of the TIGCC compiler, which don't support standard ANSI floats. See bcd for more info about internal organization of floating point values.

type bcd

bcd is a structure which represents the internal structure of floating point values. It is defined as
typedef struct
  {
    unsigned short exponent;
    unsigned long long mantissa;
  } ti_float;
Note that long long is not a typing error: it is a GNU C extension for representing very long integers (8-byte integers in this implementation). See description of bcd type in the documentation for timath.h header file for more info about the internal organization of floating point values.

Return to the main index