Pascal Newsletter #19
The full source code examples of this issue are available for download.
![]() |
![]() |
Pascal Newsletter #19 - 25-MAR-2001 INDEX 1. A FEW WORDS FROM THE EDITOR 2. DELPHI PROGRAMMING - EXPRESSION EVALUATION THE XBASE WAY - INTRODUCTION - EVALUATING EXPRESSIONS GIVEN AS STRINGS OF CHARACTERS - TO BE OR NOT TO BE, THAT IS THE QUESTION - HOW EXPRESSIONS GET EVALUATED? - AND THE VARIABLES? - WE CANNOT USE CASE...OF - BINARY SEARCH - IMPLEMENTATION OF SEARCHES BY "HASHING" - WHERE SQL HAS NOT GONE BEFORE - NOTES ABOUT THE EXAMPLE - GOING BACK TO THE PACKAGE - WHAT'S NEXT 3. CAPTURING APPLICATION MESSAGES 4. DYNAMIC ARRAYS - MULTIDIMENSIONAL DYNAMIC ARRAYS 5. DELPHI ON THE NET ARTICLES IN THE BORLAND COMMUNITY - Delphi articles · Component Building for the Professional - by Ray Konopka · Migrating from Visual Basic to Delphi - by Borland Staff · Image feathering - Lab report by Earl F. Glynn II · Effectively Using Action Lists - by Ray Konopka · Delphi math resources - Kylix articles · Are you ready for Kylix? - by David Intersimone · Adventures in Kylix - by James R. Knowles · FreeCLX source code available on SourceForge - by John Ray Thomas - Interbase articles · 30 Days from Paradox to InterBase - by Skip Rowland · InterBase V6 - Performance Enhancements - by Dave Schnepper · The ABCs of Migrating from InterBase 5 to InterBase 6 - by Mark · InterBase Install and Licensing APIs - by Inprise Staff ________________________________________________________________________ 1. A FEW WORDS FROM THE EDITOR I'm pleased to announce that the winner of the license of the JfControls Library (http://www.jfactivesoft.com) is Santiago Cubero, a young programmer from Barcelona (Spain) who had the number 62. In this issue I'm pleased to introduce another great article from Alirio Gavidia that this time will show us how to evaluate expressions at runtime in our Delphi applications. Best regards, Ernesto De Spirito eds2004 @ latiumsoftware.com ________________________________________________________________________ JfControls Library. Multi-language. Multi-appearance. Skins. Privileges. More than 40 integrated and customizable components. Impressive GUI. Centralized resources administration. Multiple programming problems solved. For Delphi 3-7 and C++ Builder 3-6. http://www.jfactivesoft.com/ ________________________________________________________________________ 2. DELPHI PROGRAMMING - EXPRESSION EVALUATION THE XBASE WAY By Alirio A. Gavidia B. INTRODUCTION ------------ A couple of years ago I was asked to solve a common "Compatibility" problem. This was to be able to evaluate xBase expressions from Delphi (by xBase we understand dBase and its derivatives like Clipper and FoxPro). All this happens because the xBase languages based all in some form of interpretation support what is known as "Macros" (don't mistake them with the storing of a series of commands and actions for future execution). EVALUATING EXPRESSIONS GIVEN AS STRINGS OF CHARACTERS ----------------------------------------------------- The application created in that opportunity asked expressions to the user as search filters for queries and reports, showing each time a button that poped up a dialog form with the elements to build an expression. The expression is of xBase type, so if the user knows this kind of applications he/she can provide the expression directly. TO BE OR NOT TO BE, THAT IS THE QUESTION ---------------------------------------- Basically there were two alternatives: 1.- Creating a control to evaluate xBase expressions. 2.- Using an existent control. The third, teaching SQL to the users, was discarded due to the principle of compatibility with the previous application. There are interesting components in this area, matter of fact I found that there are two sets of components for this: oriented to arithmetic and oriented to databases. The first ones are practical, nice, cheap (many are freeware) but they are usually oriented to the resolution of graphs and mathematical problems. The second ones consider the matter of the fields. I got interested in the components of the second kind. I ended up using a BDE replacement with support for Clipper files that accepts xBase expressions as filters. However, at the same time I developed some functions to evaluate expressions (they are in my web page and they are freeware, only documented in Spanish). As a part of this article I introduce the class TExpression. On the other hand I developed a components set (these are shareware in English and with documentation in English/Spanish) that allow to evaluate expressions like: (CUSTOMER->DOB > CTOD('01/01/1900')) .AND. CREDIT when the majority of the components that evaluate formulas don't go beyond constants expressions like: 3-2/3.14 HOW EXPRESSIONS GET EVALUATED? ------------------------------ In general there are two steps: first the analysis (search) of patterns and second the combination of the values obtained in the previous step to get a result. The patterns search (lexicography) allows to recognize in a series of characters the type and functionality of certain patterns. For example to recognize if a word starts with a digit it indicates that possibly it's a numeric literal (or an error), or otherwise the word is possibly and identifier that defines some value or operator that alters a value. Once discovered the patterns, these are stored in some data structure (normally a stack, also I've seen it with two stacks) and they get reduced combining the values according to the identifiers. In the end what remains is the result of the expression on the stack. AND THE VARIABLES? ------------------ Variables and constants and in general anything associated to an identifier has to be provided by the programmer thru an event or a list. The components I'm introducing consider both ways. They also consider arrays and functions (many predefined, mainly similar to the ones of Clipper). For example: HalSimpleExpr.Eval('Variable*Pi()'); In this case there are two identifiers "Variable" and "Pi". Since the second one is followed by a pair of parenthesis it's a function. The component fires the event OnRequestIdentifier (to evaluate Variable) and OnRequestFunction (to evaluate Pi). The evaluation of Pi would be handled this way: procedure TForm1.HalSimpleExpr1RequestFunction(Sender: TObject; ident: String; var value: Variant; var cancel: Boolean); Var col, row : integer; begin if CompareText(ident,'Pi')=0 then value := Pi else cancel := true end; Note: I must point out that there is a great absent among the parameters of the event; this is an array with the arguments of the function. In the next version the argument of the evaluated function will be part of the parameters, but for now it's just a public field of the class. You'll see that if the function isn't Pi, the control raises an exception (this is what the parameter "cancel" defines). The solution to evaluate "Variable" is analogous but with another event. All this works pretty well until we have some 50 functions. WE CANNOT USE CASE...OF ----------------------- It's not possible to use the "case" sentence since it works with "integral" types (integer, char, boolean, etc.) and the alternative to implement one "if" after the other is efficient for the first identifier but terrible for the latests. The next step is using a sorted list. BINARY SEARCH ------------- The binary search on sorted lists looks like a good alternative, if we talk of 1000 elements we can find any value in 10 steps 50% of the times (the other 50% in less). In most of the cases this is good, but there's an alternative worthy of study. IMPLEMENTATION OF SEARCHES BY "HASHING" --------------------------------------- Better than revising a list is having a function that beforehand signals the position of the identifier in the list. For example a function that adds the first character, the last minus 97 and the length of the string. This way, if we would be looking for the word "program" we would apply something like IndexOf("program") that would return Ord('p') + Ord('m') - 97 + Length('program'), that is 112 + 109 + 7 – 97 -> 131. This would mean the position 131 of the table. As you can see, the searching with "Hash" tables improve the search efforts dramatically. However, they waste memory. It's up to the programmer to define which path to follow, nevertheless the components I referred as shareware present lists of this kind as part of their intrinsic working. WHERE SQL HAS NOT GONE BEFORE ----------------------------- It happens that SQL solves very well the problems regarding filters and searching. But what happens if I wanted to make something less voluminous like a small spreadsheet with formulas definable by the user? For this purpose I'm attaching an example that uses a "StringGrid" and the class TExpression. I believe that in general there are small needs for which it it might result convenient the use of a formulas evaluator rather than intending to imitate the xBase macros. NOTES ABOUT THE EXAMPLE ----------------------- The example is a "TStringGrid" control that makes use of the properties "Cells" and "Objects". The first shows the result of a formula stored in "Objects". The "strings" have to be specified with single quotes. The files that save/load are simple text. Each defined formula requires one to press the 'ok' key to be stored. There's a defined event to handle the function "Cell(c,r)" where 'c' is the column and 'r' is the row. GOING BACK TO THE PACKAGE ------------------------- The use is simple, one method: eval. The expression is given as a string parameter. However, there are different methods according to the type to handle. The components consider different types of syntax: xBase, Basic, Pascal and Java. Fundamentally altering the use of boolean operators between dots like being done in xBase expressions. Three components with different scopes: ThalSimpleExpr, ThalMacroExpr and ThalArithmeticExpr. The first one doesn't have functions and identifiers lists management, the second implements about 75 functions, lists management and datasets references. The third one doesn't manage "aliases" nor datasets, but nevertheless it supports many of the predefined functions. The details are documented with the package and there are many examples included. I hope you enjoy it. You can download the shareware demo directly from my web page: http://www.gavidia.org/he-shareware.zip You can also ask for it to the following email address: delphi@gavidia.org. For the example attached to this article http://www.latiumsoftware.com/download/p0019.zip In http://www.gavidia.org/pod there is freeware material related with the subject. WHAT'S NEXT ----------- I'll take the time to give more information about the "hash" lists that I mentioned. That will be the subject of my next article. ------------------------------ Copyright © 2001 by Alirio A. Gavidia B. All rights reserved. The publication of this material is allowed by any means from anyone as long as this material is not modified and the original source is mentioned. ________________________________________________________________________ 3. CAPTURING APPLICATION MESSAGES Sometimes we need to capture Windows messages at an application level. One way is by a hook, and another way is by using the Message event of the Application object which is triggered every time the application gets a Windows message. We are going to follow the second path. There are two ways to set an event handler for this event: one is using an ApplicationEvents object that comes in Delphi 5 (simply double click its OnMessage combo box in the Object Inspector) and the other is doing it "by hand": 1) In the private section of your main form add the following declaration: procedure ApplicationMessage(var Msg: TMsg; var Handled: Boolean); 2) Assign the OnMessage property in the Create event of the form for example: procedure TForm1.FormCreate(Sender: TObject); begin Application.OnMessage := ApplicationMessage; end; 3) When you want to stop capturing messages all you have to do is set OnMessage to nil: procedure TForm1.FormDestroy(Sender: TObject); begin Application.OnMessage := nil; end; Finally you should implement the procedure. For example, we are going to trap the keyboard messages WM_KEYUP and WM_KEYDOWN to convert the decimal point of the numeric keypad to a comma (this is useful in Spanish applications). procedure TForm1.ApplicationMessage(var Msg: TMsg; var Handled: Boolean); begin case Msg.Message of WM_KEYDOWN, WM_KEYUP: case Msg.wParam of // Replace the period in the numeric keypad (key code = 110) // with a comma (key code = 188). 110: Msg.wParam := 188; end; end; end; Now you can drop an Edit control on your form and test it. ________________________________________________________________________ 4. DYNAMIC ARRAYS Dynamic arrays are arrays that can grow or shrink at runtime to accommodate more or less elements. The declaration of a dynamic array is much like the declaration of a static array, except that the index range is omitted. For example: var a: array of integer; A dynamic array initially has no elements. You should use the SetLength procedure in your code to assign the number of elements needed. You can call SetLength many times as needed. If the new length is greater than the current number of elements, space for new elements is added, and if it's smaller then the last elements of the array are disposed. For example SetLength(a, 10) assigns space for 10 elements. Elements in a dynamic array are indexed starting from 0 to one less the Length of the array, so for example the following code can be used to initialize the array elements to zero: for i := 0 to Length(a)-1 do a[i] := 0; In the example attached to this article you'll see the use of a dynamic array to store the names of the files in a folder. Naturally, a string list would be better for the task, but a dynamic array was used for a pedagogic purpose. MULTIDIMENSIONAL DYNAMIC ARRAYS ----------------------------- A two-dimension dynamic array can be declared this way: var a: array of array of integer; This way you can assign both dimensions at runtime. The SetLength procedure admits as many NewLength parameters as dimensions. For example SetLength(a, 10, 10) would set the size of the array to an square of 10 x 10. One interesting thing is that instead of seeing your array as a matrix (i.e. rectangular) you can see it as a vector of vectors that don't necessarily have to have the same number of elements. For example the following code creates a "triangular" array and initialize its elements with consecutive numbers: k := 0; SetLength(a, 4); // 4 rows for i := 0 to 3 do begin // For each row SetLength(a[i], i + 1); // Set the number of columns for j := 0 to i do begin // Initialize the row a[i,j] := k; inc(k); end; end; 0 1 2 3 +---+ 0 | 0 | +---+---+ 1 | 1 | 2 | +---+---+---+ 2 | 3 | 4 | 5 | +---+---+---+---+ 3 | 6 | 7 | 8 | 9 | +---+---+---+---+ ________________________________________________________________________ 5. DELPHI ON THE NET ARTICLES IN THE BORLAND COMMUNITY Some interesting things can be found in the Borland Community this month... Delphi articles =============== * Component Building for the Professional - by Ray Konopka This paper describes the critical extra steps that must be taken in order to develop professional, commercial-quality components. Specific topics will include creating online component help, effectively designing packages for component distribution, supporting multiple versions of Delphi, and how supporting automatic one-step installation. http://community.borland.com/article/0,1410,27057,00.html * Migrating from Visual Basic to Delphi - by Borland Staff http://community.borland.com/article/images/26225/vbtodelphi.pdf * Image feathering - Lab report by Earl F. Glynn II This article demonstrates how to merge a foreground and background image by fading from one image to the other, but only along a transition edge drawn with a simple drawing tool. http://www.efg2.com/Lab/ImageProcessing/Feathering.htm * Effectively Using Action Lists - by Ray Konopka This paper describes, in detail, what actions and action lists can do for an application. http://community.borland.com/article/0,1410,27058,00.html * Delphi math resources Here's an updated compendium of Delphi math resources. http://www.efg2.com/Lab/Library/Delphi/MathInfo/Resources.htm Kylix articles ============== * Are you ready for Kylix? - by David Intersimone Are you ready for Kylix? Of course you are. Is your system ready for Kylix? Here is a way to find out. http://community.borland.com/article/0,1410,26998,00.html * Adventures in Kylix - by James R. Knowles Description of a first experience with Kylix http://www.ifm-services.com/people/jamesk/kylix/ * FreeCLX source code available on SourceForge - by John Ray Thomas FreeCLX, the Open Source project for Borland's CLX Component Library for Linux, is now available for collaboration. http://community.borland.com/article/0,1410,27100,00.html Interbase articles ================== * 30 Days from Paradox to InterBase - by Skip Rowland This article reviews the problems, the band-aids, the solutions, and the successes encountered during a large database migration from Paradox to InterBase http://community.borland.com/article/0,1410,27006,00.html * InterBase V6 - Performance Enhancements - by Dave Schnepper This article will cover changes in InterBase 6 that directly or indirectly enhance throughput and general performance of queries. http://community.borland.com/article/0,1410,27005,00.html * The ABCs of Migrating from InterBase 5 to InterBase 6 - by Mark Duquette This technical article is to help you learn about the ins and outs of migrating your applications from InterBase 5 to InterBase 6. http://community.borland.com/article/0,1410,27004,00.html * InterBase Install and Licensing APIs - by Inprise Staff InterBase 6 has a new install API that automates many chores involved in embedding the database into an application. This session describes the API and how to use it. http://community.borland.com/article/0,1410,26415,00.html ________________________________________________________________________ YOU CAN HELP US We need your help to keep this newsletter going and growing. You can help by referring the newsletter to your colleagues: http://www.latiumsoftware.com/en/pascal/delphi-newsletter.php Or you can help by voting for us in some or all of these rankings to give more visibility to our web site and thus increase the number of subscriptions to this newsletter: http://www.sandbrooksoftware.com/cgi-bin/TopSite2/rankem.cgi?id=latium http://news.optimax.com/delphi/links/links.exe/click?id=70C517ECAE6E http://www.programmingpages.com/?r=latiumsoftwarecomenpascal http://www.top219.org/cgi-bin/vote.cgi?delphi&83 http://top100borland.com/in.php?who=20 http://top200.jazarsoft.com/delphi/rank.php3?id=latium http://213.65.224.200/cgi-bin/toplist.cgi/hits?Id=80 It's just a few seconds for you that REALLY mean a lot to us. ________________________________________________________________________ If you haven't received the full source code examples for this issue, you can get them from http://www.latiumsoftware.com/download/p0019.zip ________________________________________________________________________ This newsletter is provided "AS IS" without warranty of any kind. Its use implies the acceptance of our licensing terms and disclaimer of warranty you can read at http://www.latiumsoftware.com/en/legal.php where you will also find a note about legal trademarks. Articles are copyright of their respective authors and they are reproduced here with their permission. You can redistribute this newsletter as long as you do it in full (including copyright notices), without changes, and gratis. ________________________________________________________________________ Main page: http://www.latiumsoftware.com/en/pascal/delphi-newsletter.php Group home page: http://groups.yahoo.com/group/pascal-newsletter/ Subscribe/join: pascal-newsletter-subscribe@yahoogroups.com Unsubscribe/leave: pascal-newsletter-unsubscribe@yahoogroups.com Problems with your subscription? eds2004 @ latiumsoftware.com ________________________________________________________________________ Latium Software http://www.latiumsoftware.com/en/index.php Copyright (c) 2001 by Ernesto De Spirito. All rights reserved. ________________________________________________________________________ |
The full source code examples of this issue are available for download.
![]() |
Errors? Omissions? Comments? Please contact us!






