Upgrading Issues

 

See Also:  What's New in version 2.91?

 

An effort was made to preserve compatibility between version 2.0 of uCalc Fast Math Parser and this version where possible.  In a number of cases, however, it was not possible.  In order to simplify the syntax, resolve certain limitations found in 2.0, and to make this version more flexible, certain changes were required.  Except for the most minimal implementations of uCalc, it might not be possible to simply re-compile your code without modification, nor is it always simply a matter of search-and-replace to make the required changes.  Though you will likely not find the changes to be very drastic, it will still be important to browse through the following list to understand some of the key differences in how this version works.  Many of these same items listed below can be found throughout the help file in the relevant topics.

 

There are two lists:  1.  Things that have changed, and 2.  Things that are no longer supported.

 

Things that have changed

 

 

 

 

 

 

 

* The following 2.0 way of using ucDefineFunction is no longer supported:

 

ucDefineFunction "FunctionName(ParamCount)", CodeAddress

 

Functions defined this way were faster than regular callback definitions.  However, you were limited to two arguments; and they could only be numeric.  Now, for even better efficiency, use NativeCall (an advanced Language Builder feature).  This supports any kind of data type, and any number of arguments.  NativeCall allows you to define the fastest kind of callback uCalc knows how to handle, with low overhead.  For instance, arithmetic operators, trig functions, etc... are defined that way in the include file.

 

* Cryptic directives, such as &, and @ are replaced with the more descriptive directives ByExpr and ByHandle.

 

* The special variable type argument is no longer supported.  However, the new ByHandle can generally do the same thing.

 

* The $ directive for strings is no longer supported.  Use "As String" instead.  For some compilers you may need to use WideString or LPCSTR instead for your callbacks.

 

* For numeric types, # is not supported.  Instead specify Single, Long, Double, etc... for your callbacks.  If no type is specified the Extended type is used by default.

 

* It is very important in this version to remember to specify data types for function arguments, as well as the function's return value; particularly for callbacks, unless you can use the default extended precision (which is supported only by some compilers).

 

* Variable number of arguments is now denoted with three consecutive dots (...).  You can have a fixed number of arguments followed by a variable number of arguments.  In 2.0, you didn't have the choice of requiring some arguments if you also had a variable number of args.  Also, you now have the option of restricting the data type of the variable number of args.

 

* Version 2.0 imposed a special uCalc-specific form for callback functions.  All functions were to be defined with a Double return type (or Extended depending on the compiler).  Even those that actually returned a string (using ucParamStr(0) = ... or ucSetParamStr(0, ...) had to do this.  Arguments were not passed directly, but had to be retrieved using ucParam or ucParamStr.  Arguments were of either generic numeric type, or generic string type.  Now, you create your callbacks the very same way you create ordinary functions in your compiler, with the same actual data types you normally would use, and without any special uCalc code within the callback.  This allows you to attach uCalc definitions directly to Windows API routines or other routines from DLLs, without having to create a special wrapper.

 

 

* Operators can no longer be defined with ucDefineFunction.  Now, a separate function, ucDefineOperator, is used for that purpose.

 

* In 2.0 when you defined an operator, it also defined a function of the same name.  It is no longer done that way.  When you define an operator, it will only work in the capacity of an operator.

 

* ucReleaseExpr was removed, and replaced with ucReleaseItem.  IMPORTANT:  You should not merely replace occurrences of ucReleaseExpr in your code with ucReleaseItem, as they work very differently.  The old ucReleaseExpr was capable of releasing expressions only in sequential order.  And if you supplied an argument (which was optional), it would release that number of recent expressions.

 

With the new ucReleaseItem, you can release individual items in any order.  The argument passed to ucReleaseItem is the handle of the specific item you want to release.  Anything you can define (an expression, function, variable, thread, syntax, pattern, etc...) is now an item.  Each item has a handle, and can be released using this handle.

 

* Examples in version 2.0 showed that you could call ucReleaseExpr immediately after ucParse, even before calling ucEvaluate.  That was OK in version 2.0, because ucReleaseExpr simply set a marker for the data to be overwritten later.  However, now, ucReleaseItem actually releases the item from memory immediately, after which you cannot use the item any more. 

 

* An item that is incorrectly defined is automatically released, and has a handle of 0.  ucReleaseItem(0) simply does nothing.  So it is always OK to release an item, without first checking to see if it has a non-0 handle.

 

* ucReleaseVariable was also removed and replaced with ucReleaseItem.  The help file in version 2.0 mentioned an extra step to take when releasing a string variable.  That step is no longer necessary.

 

* ucReleaseItem as defined in the include file releases an item by handle.  To release an item by name, simply use uCalc(uc_ReleaseItem, "MyItem"), where MyItem is the name of your variable, function, or any other named item.

 

* Releasing everything.  Apparently many users used ucReset in this way due to the limitations of ucReleaseExpr.  In such cases, you can now use the more flexible ucReleaseItem.  However, you still can release everything defined in a given thread (including its sub-threads), by invoking ucReleaseItem with the handle of the thread you want to release.  Be careful when releasing the default thread, as you might need to re-define everything as found in the Initialization section of the include file (since there are no "built-in" operators, functions, syntax, etc...).

 

* Allocating definition space.  This is now irrelevant, as definition space is allocated automatically as you go along.  You do not have to allocate a maximum chunk of memory ahead of time and worry about whether you might reach that limit.

 

* Setting Relational True.  The Language Builder does not have "built-in" relational operators.  However, the same library from which FMP's relational operators are defined also has a provision for changing the True value.  ucAddr(uc_True) contains a 32-bit memory address that contains the value for True.  The default is now -1 instead of 1.

 

* Precedence level.  Each operator can now be defined with its own precedence level at the moment it is defined.  Still, you can set/retrieve the default level by calling uCalc() with uc_GetDefaultPrecedence or uc_SetDefaultPrecedence if you want.  However, explicitly assigning a level in each operator definition is recommend.  Even after an operator is defined, you can change its precedence level with the uc_Precedence command in uCalc().  Precedence levels can be any arbitrary positive integer value less than 2^31, deriving its meaning by whether this value is greater or less than the precedence levels of other given operators.  In 2.0, you were limited to values between 1 and 22 (which was the level range of hard-coded built-in operators).

 

* Precedence levels for operators are no longer hard-coded.  They are defined in the include files.  You can change the levels there, or you can even change them during runtime.  In version 2.0, you could only set the precedence levels for user-defined operators, and then it was one level for all user-operators.

 

* DecimalSeparator and ArgumentSeparator.  Use ucDefineSyntax for this instead.

 

 

* Technically the uCalc Language Builder does not have "built-in" support for strings, or any kind of data type for that matter.  Instead it allows you to define data types yourself.  A library of common types from which to choose from is included in the DLL, so you don't have to start entirely from scratch.  String types chosen in the include file for uCalc FMP (you can add to, remove, or rename them as needed), include:  String (dynamic multi-byte ansi string; default), WideString (Unicode), LPCSTR (null-terminated), and FixedString (fixed length strings).  You must specify an appropriate string type, especially for callback definitions.  See the demo file for your compiler to see which kinds of string types are appropriate for your callback routines.

 

* The $ character no longer designates a function or argument as a string during definition.  Instead, use "As String" (or As LPCSTR, etc...).  If you are using the Language Builder, you can define a syntax that uses the $ in the same way as BASIC, if you prefer.  (The usage of $ in version 2.0 was vaguely reminiscent of, but not consistent with the $ string notation of BASIC).

 

* ucSetParamStr(0, ...) is replaced with ucReturnStr.  ucParam is replaced with ucParamDbl or ucParamLng.  ucParamStr is still there, but there is a better way of retrieving arguments.  You can now define your callbacks the way you normally would define a function in your compiler.  And from uCalc, simply choose the matching string type as described in the previous paragraph.  If you pass a uCalc String ByExpr, instead of ByRef or ByVal, then your callback can retrieve it as a generic string with ucEvaluateStr, as with the MyIIFStr in the demo.

 

* The single quote (') and double quote (") delimiters for string literals were hard-coded in version 2.0.  Now, this syntax is defined in the include file, and can be changed either there, or during runtime.

 

* The & operator is no longer hard-coded as a concatenation symbol, nor is the Concatenate() function, though you are free to define them again (there are several ways of doing this).

 

* Passing a string argument in place of a numeric expression where a ByExpr (formerly expression type) argument is expected is no longer supported.  Instead you can define a ByExpr argument As String, or as any other given numeric or other type.  It would no longer make sense for uCalc to force a string arg to convert into a numeric expression if that's not your intention.  You can simulate the old behavior by receiving a string and using ucEvalStr on the argument once inside the callback.

 

 

Also, you have full control of the FPU word, which can for instance, decide whether 1 / 0 should raise an error, or be treated as the numeric value of Infinity.  The demo shows one of the ways to control the FPU.

 

Something important to all users, even if you don't care anything about FPU control per se, is that uCalc maintains a separate FPU word from your host program, and both are insulated from each other.   The end result is that this resolves a problem that some users reported, which was caused by their host program changing the FPU setting (without the programmer being aware), and preventing uCalc from working.

 

Overflow, Underflow, and other FPU exceptions can directly be controlled by uCalc.

 

 

 

 

Features that are no longer supported

 

 

 

There are in fact no longer any "built-in" functions, operators, or constants at all.  Some common items, such as arithmetic, trigonometric, and miscellaneous items are included in a library in the DLL, and are activated in the include file.  You can remove, rename, or add items to the list.  You can implement new items using the same kind of NativeCall procedure callbacks (an advanced Language Builder feature) as the ones in the library, achieving the same maximum speed.  (Standard procedures, which are easier to implement, can be defined as well, and are generally sufficiently fast).