How to make a program which returns a value like a TI-Basic function
Re-read this section carefully even if you are already familiar with this
feature from TIGCCLIB 1.5!
Starting from the release 1.5 of the TIGCC library, it is possible to write programs
which return a value to the TI-Basic, i.e. which act like TI-Basic function (but note
that there are some serious limitations if you want to do this; read below for more
info). To do this, put the following statement at the begining of the program (or
at the begining of the main module of your program):
#define RETURN_VALUE
This will work in both "nostub" and "Doors" modes. Such statement will cause
that the last value pushed to the expressions stack would become the "result"
of the program. For pushing values on expressions stack use routines from
estack.h header file. For example, use
push_longint to push integer values,
push_Float to push floating point values,
push_string and push_ANSI_string
to push strings, etc. Note that if you declared RETURN_VALUE
,
you must push something on the stack.
Recently, I received the important information from Kevin Kofler. If you plan to write a
function which returns a value to TI-Basic in either Assembly or C, you should also clean up
all arguments of the function from the expression stack before pushing the result including
the END_TAG. If you neglect doing this, then using the
function as an argument of another one will not work correctly. Also, you should leave exactly
one value on the expression stack (i.e. you should delete any eventual temporary result from
the stack). Here is a sample code how you can clean up function arguments from the expressions
stack:
while (GetArgType (top_estack) != END_TAG)
top_estack = next_expression_index (top_estack);
top_estack--;
Here is a complete example of
very simple program which gets two arguments (assuming that they are small
positive integers, without any checking), and returns their sum (see
args.h for more info about getting the arguments):
#define RETURN_VALUE
#include <args.h>
#include <estack.h>
int _ti89, _ti92plus;
void _main(void)
{
ESI argptr = top_estack;
int a, b;
a = GetIntArg (argptr);
b = GetIntArg (argptr);
while (GetArgType (top_estack) != END_TAG)
top_estack = next_expression_index (top_estack);
top_estack--;
push_longint (a+b);
}
Test this program from TI-Basic by giving add(2,3)
(assuming that
you compiled it and gave the name "add.c" to it). Note that if you neglect cleaning
up arguments from the expressions stack, then something like
add(add(3,5),add(4,7))
will not give the correct result!
You can return even lists as the result. To do this, push first
End_Of_List marker (using push_END_TAG), then
push elements of the list in the reverse order, and finnaly push List marker on the
expressions stack using push_LIST_TAG. The following
program returns the list of all variables in the folder which is given as the argument:
#define RETURN_VALUE
#include <args.h>
#include <estack.h>
#include <vat.h>
int _ti89, _ti92plus;
void _main(void)
{
ESI argptr = top_estack;
SYM_ENTRY *SymPtr = SymFindFirst (GetSymstrArg (argptr), 1);
while (GetArgType (top_estack) != END_TAG)
top_estack = next_expression_index (top_estack); // clean-up args
top_estack--;
push_END_TAG ();
while (SymPtr)
{
push_ANSI_string (SymPtr->name);
SymPtr = SymFindNext ();
}
push_LIST_TAG ();
}
Give the name "dir.c" to it, compile it using
tigcc -O2 dir.c
then try, for example, dir("main")
from the TI-Basic. Happy? Many
users asked me how to make such program!
Now about problems. Everything works fine on AMS 1.xx, but AMS 2.xx forbids usage of
ASM programs in expressions. So, in the above example, 'add(2,3)'
will
work perfectly, but '5+add(2,3)'
or even
'add(2,3)->a'
will not. This stupidity
makes returning values mostly useless. What to do? Unfortunately, I can't do nothing
from the TIGCC itself, because an ASM program will not be executed at all if AMS 2.xx
detects its presence in an expression. However, there is a solution: it is possible to
make a resident program which will intercept such "stupid" behaviour of AMS 2.xx and to
allow executing ASM programs in expressions. Such interception is already implemented
in the latest versions of DoorsOs and Universal OS (but not in TeOS). So, if you have
installed a fresh release of Doors or UniOS, everything will work OK even on AMS 2.xx.
This does not mean that your program must be compiled in "Doors" mode: it may be a
"nostub" program, but DoorsOS or Universal OS must be present on the calculator (to
intercept stupid behaviour of AMS 2.xx). To conclude: if you have AMS 2.xx and if you
want to use "returning a value" feature, you must have installed Doors or UniOS. If
you are a program maker, please note this fact in the documentation of any program
which uses this feature!
As an alternative, you may use returning values
trough variables.