ArtFormula v1.0b


ArtFormula package contains two nonvisual Delphi component for symbolic expression parsing and evaluation. Provides runtime scripting engine for automating your programs.

TArtFormula description

Properties:

property Error : TFormulaError; - returns current error code.

TFormulaError = (ER_Ok, ER_ILLEGAL, ER_UNKNOWN, ER_RIGHT, ER_LEFT, ER_SYNTAX, ER_VARS, ER_NOTENOUGH);

property ErrPos : integer; - returns position of error.

property ErrLine : integer; - returns the line with error.

property ErrStrPos : integer; - returns the position of error inside source string.

property Stop : boolean; - set Stop to true during computation to stop.

propertyy Compiled : string; - byte code of compiled source string.

Published properties:

property UnQuotedString : boolean; - if true, ArtFormula will consider unknown identifiers as string literals.

property TestUsedVars : boolean; - if true, ArtFormula will test whether all external variables, passed as vars parameter of Compile or Test procedure, are used in source expression.

property CaseSensitive : boolean; - if true, ArtFormula will distinguish case of characters in variables name. Note: functions names are always case insensitive.

property Step : boolean; - if true, you can stop computation, by setting Stop property to true. If false you can't stop computation until it ends.

Methods:

procedure SetVar(name : string; value : PCalcItem); - sets value of variable, given by name parameter.

function GetVar(name : string) : PCalcItem; - returns value of variable.

function IncVar(name : string) : PCalcItem; - increments value of a variable.

function DecVar(name : string) : PCalcItem; - decrements value of a variable.

procedure AddVar(name : string; value : PCalcItem); - adds internal variable.

procedure AddUserConstant(name, value : string); - adds new constant.

function AddUserFunction(name : string; paramcount:integer; fun : pformulafunction; ismodule:boolean=false):PTableItem; - adds user function (see Section creating user functions and modules).

function AddModuleFunction(module: PTableItem; name : string; paramcount:integer; fun : pformulafunction; ismodule:boolean=false):PTableItem; - adds module function (see Section creating user functions and modules).

function Test(instr : string; num : byte = 0; vars : PStringArray = nil) : boolean; - tests syntax of source code represented by instr. External variable names are passed as vars parameter, num specifies number of external variables. Returns true if there are no errors.

function Compile(instr : string; num : byte = 0; vars : PStringArray = nil) : string; - compiles source string and returns compiled byte code. On error raises exception.

function ComputeN(num : byte = 0; vals : PCalcArray = nil) : double; - compute previously compiled program and returns result as numeric value. Values of extern variables are passed in vals parameter, the number of values is passed in num value.

function Compute(num : byte = 0; vals : PCalcArray = nil) : string; - compute previously compiled program and returns result as string value.

function ComputeStrN(instr : string; num : byte = 0; vars : PStringArray = nil; vals : PCalcArray = nil) : double; - compiles and computes source string. Returns result as numeric value.

function ComputeStr(instr : string; num : byte = 0; vars : PStringArray = nil; vals : PCalcArray = nil) : string; - compiles and computes source string. Returns result as string value.


How to use

Write ArtFormula program (see Section ArtFormula Syntax). Prepare string array with external variable names. Prepare TCalcArray with variable values. Use setN and setS procedures.

TFormulaDataType = (fdtnumber, fdtstring);

TCalcItem = record
data : double;
str : string;
typ : TFormulaDataType;
end;

TCalcArray = array of TCalcItem;
PCalcArray = ^TCalcArray;

Use AddUserConstant, AddUserFunction and AddModuleFunction procedures to add constants, user and module functions.

Call Test and/or Compile procedures passing source code as instr parameter, number of external variables in num parameter and pointer to array of variable names in vars parameter. If there no errors, call Compute or ComputeN (depending on desirable result type) procedure, passing number of values in num parameter and pointer to variable values in vals parameter.

To compile and compute expression by one call use ComputeStrN or ComputeStr procedures.


Creating user functions and modules

TArtFormula has AddUserFunction and AddModuleFunction procedures allow you to add user defined functions and modules. AddUserFunction takes three or four parameters: function name, number of parameters, pointer to corresponded Delphi function and flag whether function is main function of new module.

First you should write Delphi function of next type:

function MyFunction(var Calc : TFormulaCalc):TCalcItem;

This function should return result of TCalcItem type. If function returns string value, set str member of Result variable and set typ member to fdtstring else set data member and typ to fdtnumber. Use setN and setS procedures to do it.

Function take one parameter of TFormulaCalc type. TFormulaCalc is stack object used to implement arithmetical and logical calculation. It has many methods and properties but most useful are:

function TopN: double; - returns top value as number.

function TopS: String; - returns top value as string.

function ItemN(i:integer):double; - returns stack item value as number. ItemN(0) - top element, Item(1) - next and so on.

function ItemS(i:integer):string; - returns stack item value as string.

function Item(i:integer):PCalcItem; - returns pointer to stack item.

property Parent : TArtFormula; - pointer to parent ArtFormula object.

You should understand, that parameters for function are passed in stack. So last function parameter is the top (Item(0)) item in stack. For example if function has three parameters first parameter will be ItemN(2) or ItemS(2), second - ItemN(1) or ItemS(1), third - ItemN(0) or ItemS(0) (TopN or TopS).

If you want to create variable argument list functions, you should pass -1 as paramcount to AddUserFunction. For such functions ArtFormula pass the number of parameters as last argument (top in Calc stack).

TArtFormula has special type of function called module. Module can have its own functions. Module can be considered as functions library or as object with methods and properties.

To create module, call AddUserFunction setting module parameter to true. It creates main function of module. AddUserFunction returns pointer to new allocated function table item which should be passed as first argument of AddModuleFunction when you add function to the module. The name of function passed to AddUserFunction becomes the name of the module. You can call main function of module in ArtFormula program as usual function. The call of other module function should be preceded by module name and period (.). If you pass arguments to main function of module, ArtFormula first calls main function. For example:
module('x').fun('y') - calls main function with argument 'x' and then function fun with argument 'y';
module.fun('y') - calls only function fun with argument 'y'.

The result of main function of module is passed as additional (first) argument of other module function. This feature allows one to use modules as objects. The common way to do so is to create internal table of objects, write module function which creates new entry in table and returns index. Main module function takes one parameter - index of object in internal table and simply returns it. This index is passed as first parameter to other module functions, so it is known with which object deal with.

For example:

$f := file.new; // creates new file object
file($f).name := 'info';
file($f).open('read');

ArtFunction module can't have data members but you can easily create properties. To create property with name SomeName you should write two function. First with name SomeName without parameters which returns property value and second with name SetSomeName with one parameter which sets property value. So when ArtFormula meets statement module.SomeName := Val it automatically compiles it as module.SetSomeName(Val).

See File module (af_file.pas in demo folder) as example of module developing.


ArtFormula Syntax

Preamble

ArtFormula has no statements in common meaning. All program structure elements (branching, loops) are realized as function calls. So every statement has parameters and result value. For example pascal block statement (begin ... end) is realized as block(...) function, if statement is call of condition() function. TArtFormula component has predefined constant so you can use pascal like notation instead of function calls. Also you can use semicolon instead of comma. Below we will show both (function call and statement like) syntax for all programming abilities of ArtFormula.

Comments

Comments are ignored by TArtFormula compiler. There are two ways to construct comments: text between a left brace and a right brace constitutes a comment. Any text between a double-slash and the end of the line constitutes a comment.

Types end Expressions

ArtFormula has the only data type. Depending on expression ArtFormula treats data value ether as numeric or string type. For comparison operation (=, <> ,>= , <= , >, <) and addition ArtFormula tries to convert operand first to numeric values and if this impossible to string. For example: "123" + 321 returns 444, but "x123" + 321 results in "x123321".

Numeric literals (integer and real) can be represented in common decimal notation. The dollar-sign prefix indicates a hexadecimal numeral. The first hexadecimal digit after $ must be one of 0..9 - for example $0AF (not $AF).

String value can be enclosed both in double and single quotes. Two sequential apostrophes or double quotes in a same quoted string denote a corresponded single character. To specify symbol with special ASCII code use # symbol followed by corresponded integer constant.

There is no boolean type. As in C language ArtFormula treats zero value as False and nonzero as True.

Date and time are represented as floating point value.

Operators

Numeric operators: +, - , * , /, % (or mod), \ (or div), ^ (raising to a power).

Comparison operators: =, <>, >, <, >=, <=.

Logical operators: & (or and), | (or or), xor, ! (or not).

Concatenation operator: @.

Difference in addition and concatenation operations is that @ always treats its operands as strings, i.e. "123" @ 321 results in "123321" (unlike it "123" + 321 returns 444).

Constants

You can't define new constant in ArtFormula program. But you can add constant by AddConstant procedure of TArtFormula component. Constant in ArtFormula is not the same as in pascal. It more close to C #define. If ArtFormula compiler meets constant, it replaces constant with corresponded value. So you can define constant not only to specify numeric or string values but also for token replacement.

For example you can define constant MyIf equals to If x=0 then return(0) endif and use MyIf as new statement.

Predefined functions

As ArtFormula descended from simple expression evaluation class, it has a wide number of predefined functions.

Numeric functions:

Trigonometric, hyperbolic and invert functions:
sin(x), cos(x), tan(x), asin(x), acos(x), atan(x), cosh(x), sinh(x), tanh(x), asinh(x), acosh(x), atanh(x)
Exponential and logarithmical functions:
log(x), lg(x) (log base 10), exp(x), sqrt(x)
Integer and factional part of number: int, frac
Absolute value: abs
Sign of a number: sign
Random value and initialization of the random number generator: rnd(x), randomize

Statistical functions (all statistical functions take variable argument list):

max(x1,x2,...) - maximum of passed values,
min(x1,x2,...) - minimum of passed values,
avg(x1,x2,...) - average value,
stddev(x1,x2,...) - standard deviation (unbiased),
stddevp(x1,x2,...) - standard deviation (biased),
sum(x1,x2,...) - sum of passed values,
sumofsquares(x1,x2,…) - sum of passed values squares
count(x1,x2,...) - count of passed values
variance(x1,x2,...) - variance (unbiased)
variancep(x1,x2,...) - variance (biased)

Logical functions:

iff(e,x,y) - checks the expression passed as e and returns x if it evaluates to true, or y if it evaluates to false.
isnumber(x) - returns true if x is number.

String functions:

chr(x) - returns character with ASCII code x.
length(s) - length of the string.
trim(s), trimleft(s), trimright(s) - trims leading and/or trailing spaces and control characters from a string
uppercase(s), lowercase(s) - converts an ASCII string to upper(lower)case.
midstr(s,fron,len), leftstr(s,len), rightstr(s,len) - returns the substring of a specified length that appears at the specified position (start, end) of a string.
pos(t, s) - returns the index value of the first character of t that occurs in s.
code(s) - returns then returns ASCII code of first character of string s.
stringofchar(c, count) - returns a string with a specified number of repeating characters

Date and Time functions:

date(s) - converts string to numeric date-time value.
now - returns the current date and time.
dayofweek(d) - returns the day of the week represented by a value d. Returns a value between 1 and 7, where 1 indicates Monday and 7 indicates Sunday.
year(d), month(d), day(d), hour(d), minute(d), second(d), millisecond(d) - returns corresponded part of date-time value d.
isleapyear(n) - indicates whether a specified year n is a leap year.
encodedate(year, month, day) - returns a date-time value that represents a specified year, month and day.

Formatting functions:

format(s,x) - formats a floating point value x using the format string given by s. Uses the same format string as format Delphi FormatFloat function.
formatf(s,x) - formats a floating point value x using the format string given by s. Uses the same format string as format Delphi Format function.
formatdate(s,d) - formats a date-time value d using the format string given by s. Uses the same format string as format Delphi FormatDateTime function.

Dialog functions:

input(caption, prompt, val) - displays an input dialog box that lets the user enter a value.
msg(text, caption, flags) - displays a specified message to the user.

User functions and Modules

Present version of ArtFormula do not provides subroutines in ArtFormula programs. But you can use AddUserFunction and AddModuleFunction procedures do add new functions and modules to ArtFormula. User functions are called in the same way as predefined functions. The call of module function should be preceded by module name and period (.). If module name followed by parenthesis with parameters then ArtFormula calls main function of module first.

For example: module('x').fun('y') - calls main function of module with argument 'x' and then function fun with argument 'y'; module.fun('y') - calls only function fun with argument 'y'.

Variables and arrays

ArtFormula has two kinds of variables external and internal. External variables are passed as argument of Compile procedure. You can reference that kind of variables by name.

Internal variables are defined in ArtFormula program. There are two functions to define variable:

define("name", value) and defines("name1", "name2", "name3", ...).

Instead of defines() you can use next syntax:

var "name1", "name2", "name3", … end.

To get/set value of variable use functions:

get("name") and set("name", value).

In place of get("name") you can use $name, and in place of set("name", value) - $name := value.

As set and get are functions, you can use an expression to specify variable name. Corresponded alternative syntax is $(expression).

ArtFormula provide two special functions for variable incrementing and decrementing:

inc('name') and dec('name'). Instead of function call you can use next syntax: $name++ and $name--.

ArtFormula does not provide arrays, but can work with variables named 'n1', 'n2', 'n3' ... as with array. To reference element of such "array" use expression $('arrayname'@index) or $arrayname[index] for example $n[$i]. Two dimensional arrays should consists of variables 'x1_1', 'x1_2', 'x2_1' and so on. To reference element: $x[$i,$j] (equal to $('x'@$i@'_'@$j)). You can define multidimensional arrays in the same way.

Statements

ArtFormula has five special functions treated as statements. In fact these functions are not real functions as compiled in special byte code.

Return procedure:

return(value) - stops evaluation and return value as a result of computation.

Compound statement:

block(p1,p2,p3,…) - returns value of last argument.

Predefined constants:

begin = block(
end = )

Corresponded alternative syntax:

begin p1; p2; p3; … end.

If statement

condition(expression, p1, p2) - returns p1 or p2 depending of expression value.

Predefined constants:

if = condition(
then = ,begin(
else = ),begin(
endd = ))
endif = ),0)

Corresponded alternative syntax:

if expression then p1 else p2 endd or
if expression then p1 endif.

Pay attention that in first case statement should ends with endd as in fact if expression then p1 else p2 endd is equal to condition(expression, block(p1), block(p2)).

Difference between condition and iff functions is that iff computes both its branches and condition only one. For example

iff(1,message('1','1',0),message('0','0',0)) shows two message boxes and
if 1; message('1','1',0); message('0','0',0) end shows only first message box.

While statement

loop(expression, p)

Predefined constants:

while = loop(
do = ,begin(
wend = ))

Corresponded alternative syntax:

while expression do p wend.

Repeat statement

till(p, expression)

Predefined constants:

repeat = till(begin(
until = ),

Corresponded alternative syntax:

repeat p until expression end.

For statement

series(initialization, condition, increment, p)

Predefined constants:

for = series(
next = ))

Corresponded alternative syntax:

for initialization; condition; increment do p next

For statement in ArtFormula is equal to C iterative loop. For example:

for $i := 1; $i <= 10; $i++ do $x[$i] := $i; next

All loop functions return the number of iteration done.

Using ArtFormula

As all ArtFormula statements are functions call, you can use them in any expressions. For example next statements are correct for ArtFormula.

$a := $b := 2;
$a := begin $c:=100; while $c>10 ; $c-- end; $c-3 end;
for begin $a:=1; $c:=10 end; $a<10; begin $a++; $b++ end; $c--; end;


TArtFormulaN

ArtFormula package includes another component TArtFormulaN. This component is forerunner of TArtFormula.
TArtFormulaN can only evaluate numeric expressions. It doesn't supports strings, arrays, modules, scripting, but it much faster (about five times) then TArtFormula. So you may wish to use TArtFormulaN when you need quick numeric computation along with ability to specify expression in symbolic notation in runtime.

TArtFormulaN supports only the next functions:
sin, cos, tan, log,lg, exp, sqrt, int, frac, abs, atan, asin, acos, asinh,acosh,atanh,cosh,sinh,tanh, sign, rnd, max, min, avg, stddev, stddevp, sum, sumofsquares, count, variance, variancep, iff.

Unlike TArtFormula user defined functions for TArtFormulaN takes two parameters: (pos : integer; var data : array of double). Array represents a calculator stack and pos - position of stack top. So data[pos] is last parameter, data[pos-1] - next to last and so on. User defined function should returns result of double type.


History

First version of C++ class Formula (forerunner of TArtFormula) was written for Borland C++ compiler about 1997. Later it was ported to DJGPP environment and then to Borland C++ Builder. I've used Formula class for numeric research both in my master thesis (1999) and PhD dissertation (2002). About December 2004 I've decided to translate C++ Formula class to Delphi. Thus first version of pascal class TArtFormula was developed. Now this version is renamed to TArtFormulaN. In the middle of 2005 I've realized that I should extend ArtFormula syntax and add string handled functions to meet my requirements. So present beta version of TArtFormula Delphi component was released.


Author

Artem V. Parlyuk, e-mail:artsoft@nm.ru, http://artsoft.nm.ru


License and disclaimer agreement

IMPORTANT - READ CAREFULLY

This license and disclaimer statement constitutes a legal agreement ("License Agreement") between you (either as an individual or a single entity) and Artem Parlyuk (the "Author"), for this software product in this particular case TArtFormula Delphi package ("Software"), including any software, media, and accompanying on-line or printed documentation.

BY DOWNLOADING, INSTALLING, COPYING, OR OTHERWISE USING THE SOFTWARE, YOU AGREE TO BE BOUND BY ALL OF THE TERMS AND CONDITIONS OF THIS LICENSE AND DISCLAIMER AGREEMENT. If you do not agree with the terms and conditions of this agreement, you must promptly cease all use of the software and destroy all copies of this software and all of its component parts in your possession or under your control.

This Software is owned by Author and is protected by copyright law and international copyright treaty.

This Software is freeware. You are granted the permission to use Software in your own applications for private or commercial purposes, provided your software contains the copyright notice "TArtFormula Delphi package Copyright (c) by Artem Parlyuk" and link to the Author site (http://artsoft.nm.ru) and Author e-mail (mailto:artsoft@nm.ru) .

You can freely distribute copies of the main archive as long as no alterations are made to the contents and no charge is raised except a reasonable fee for distributing costs. You may not remove copyright notices from copies of the Software. You may not claim this Software as written by anyone but Author, Artem Parlyuk.

The author has taken all possible care to ensure the software is error-free, however the author disavows any potential liability arising from any use of the software. This software is provided "as is" and without any warranties expressed or implied, including, but not limited to, implied warranties of fitness for a particular purpose, and non-infringement. You expressly acknowledge and agree that use of the Software is at your sole risk.

In no event shall the author be liable for any damages whatsoever (including, without limitation, damages for loss of business profits, business interruption, loss of business information, or other pecuniary loss) arising out of the use of or inability to use this software or documentation, even if the author has been advised of the possibility of such damages.

Any feedback given to the Author will be treated as non-confidential. The Author may use any feedback free of charge without limitation.