& Macro evaluation--unary (Special) ------------------------------------------------------------------------------ Syntax &<cMacroVar>[.] &(<cMacroExp>) Operands <cMacroVar> can be any character variable. The period (.) is the macro terminator and indicates the end of the macro variable and distinguishes the macro variable from adjacent text in the statement. <cMacroExp> is a character expression enclosed in parentheses. In this instance, the expression is evaluated first, and the macro operation is performed on the resulting character value. This allows the contents of fields and array elements to be compiled and run. Description The macro operator in CA-Clipper is a special operator that allows runtime compilation of expressions and text substitution within strings. Whenever the macro operator (&) is encountered, the operand is submitted to a special runtime compiler (the macro compiler) that compiles expressions, but not statements or commands. Text Substitution Whenever a reference to a private or public macro variable, embedded in a character string, is encountered, the variable reference is replaced by the content of the macro variable. For example, cMacro := "there" ? "Hello &cMacro" // Result: Hello there If you specify a macro expression (e.g., &(cMacro1 + cMacro2)), and the macro variable is a local, static, field variable, or an array element, it is treated as literal text and not expanded. Macro operator:nesting Compile and Run When a macro variable or expression specified within an expression is encountered, it is treated like an expression, with the macro symbol behaving as the compile and run operator. If the macro is specified as a macro variable, cMacro := "DTOC(DATE())" ? &cMacro the macro compiler compiles, then executes the content of the macro variable. The compiled code is then discarded. If you specify an expression enclosed in parentheses and prefaced by the macro operator (&), ? &(INDEXKEY(0)) the expression is evaluated and the resulting character string is compiled and run as a macro variable. Using the macro operator, you can compile a character string containing a code block definition: bBlock := &("{ |exp| QOUT(exp) }") The run portion of the operation returns the code block as a value. You may then use the code block by invoking it with the EVAL() function. This is especially significant in activations that involve extensive looping through user-defined conditions (operations that in earlier versions of CA-Clipper required macro expansion). In those versions, the macro expression was compiled and run for each iteration of the loop. With the combination of a macro expansion and a code block EVAL(), the compilation is performed once at compile time, and the EVAL() merely executes the code block each time through the loop: EVAL(bBlock, DATE()) The time savings at runtime can be enormous. Notes . Command keywords: You cannot use the macro operator (&) to substitute or compile command keywords. However, you can redefine command keywords by modifying the command definition in Std.ch, overriding an existing command definition with a new definition using the #command directive, or redefining a command keyword using the #translate directive. In any case, you may redefine a command keyword only at compile time, not at runtime. . Command arguments: In prior versions of CA-Clipper as well as in other dialects, you could use macro variables as the arguments of commands requiring literal text values. These included all file command arguments and SET commands with toggle arguments. In these instances, you can now use an extended expression enclosed in parentheses in place of the literal argument. For example, xcDatabase = "Invoices" USE &xcDatabase. can be replaced with: xcDatabase = "Invoices" USE (xcDatabase) It is important to use extended expressions if you are using local and static variables. Generally, commands are preprocessed into function calls with command arguments translated into function arguments as valid CA-Clipper values. File names in file commands, for instance, are stringified using the smart stringify result marker and passed as arguments to the functions that actually perform the desired actions. If you specify a literal or macro value as the command argument, it is stringified. If, however, the argument is an extended expression, it is written to the result text exactly as specified. This example, #command RENAME <xcOld> TO <xcNew>; =>; FRENAME( <(xcOld)>, <(xcNew)> ) // RENAME &xcOld TO &xcNew RENAME (xcOld) TO (xcNew) is written to the result text as this: FRENAME( "&xcOld", "&xcNew" ) FRENAME( xcOld, xcNew ) when preprocessed. When the macro variables are stringified, the macro variable names are hidden in the string and not compiled. Later, at runtime, they are substituted into the string and passed as arguments to the FRENAME() function. This precludes local and static macro variables since the names of the variables are not present at runtime to be substituted. Public and private variables, however, behave as expected. . Lists as arguments of commands: The macro operator (&) will not fully substitute or compile a list as an argument of most commands. In particular, these are commands where an argument list is preprocessed into an array or a code block. Instances of this are arguments of the FIELDS clause and SET INDEX. An exception is the SET COLOR command which preprocesses the list of colors into a single character string and passes it to the SETCOLOR() function. In any case, list arguments should always be specified as extended expressions with each list argument specified: LOCAL xcIndex := { "Ntx1", "Ntx2" } SET INDEX TO (xcIndex[1]), (xcIndex[2]) . Arrays: You can use the macro operator (&) with arrays and array elements. However, because of the increased power of CA-Clipper arrays, you may find less need to use the macro operator (&) to make variable references to arrays. You can now assign array references to variables, return array references from user-defined functions, and nest array references within other arrays. You may also create arrays by specifying literal arrays or using the ARRAY() function. You can, therefore, make references to arrays and array elements using both macro variables and macro expressions with the restriction that you cannot make the subscript references in a PRIVATE or PUBLIC statement. Also, you cannot specify the macro operator (&) in a declaration statement, such as a LOCAL or STATIC statement. Attempting this will generate a fatal compiler error. This example references array elements using macro variables: cName := "aArray" nElements := 5 cNameElement := "aArray[1]" // PRIVATE &cName.[nElements] // Creates "array" with 5 // elements &cNameElement. := 100 // Assigns 100 to element 1 &cName.[3] := "abc" // Assigns "abc" to element 3 You can successfully apply a macro operator (&) to an array element if the reference is made using a macro expression. A macro variable reference, however, will generate a runtime error. For example, the following lists the values of all fields of the current record: USE Customer NEW aStruc := DBSTRUCT() // FOR nField := 1 TO LEN(aStruc) ? &(aStruc[nField, 1]) NEXT . Code blocks: You can apply the macro operator (&) to a macro variable or expression in a code block in most cases. There is a restriction when the macro variable or macro expression contains a declared variable. A runtime error occurs if you specify a complex expression (an expression that contains an operator and one or more operands) that includes the macro operator (&) within a code block. This has important implications for the use of local and static variables in the conditional clauses of commands, since these clauses are blockified as they are written to the result text during preprocessing. This applies to all FOR and WHILE clauses, the SET FILTER command, and the SET RELATION linking expression. The general workaround is to gather the entire expression into a single macro variable then apply the macro operator (&) to the variable. . Macro conditions: When using the macro operator (&) to specify conditional clauses of database commands such as FOR or WHILE clauses, there are some restrictions based on the expression's complexity and size: - The maximum string size the macro compiler can process is 254 characters. - There is a limit to the complexity of conditions (the more complex, the fewer the number of conditions you can specify). . Procedures and functions: You can reference procedure and function calls using macro variables and expressions. With DO, the macro variable reference to the procedure can be all or part of the procedure name. With a call to a function (built-in or user- defined), the macro variable reference must include the function name and all of its arguments. In CA-Clipper, because of the added facility code blocks, all invocations of procedures and functions using the macro operator should be converted to the evaluation of code blocks. This code fragment cProc := "AcctsRpt" . . . DO &cProc can be replaced with: bProc := &( "{ || AcctsRpt() }" ) . . . EVAL(bProc) The advantage of a code block over a macro evaluation is that the result of the compilation of a string containing a code block can be saved and, therefore, need only be compiled once. Macro evaluations compile each time they are referenced. . References into overlays: You must declare procedures and user-defined functions that are used in macro expressions and variables but not referenced elsewhere as EXTERNAL, or the linker will not include them into the executable (.EXE) file. . TEXT...ENDTEXT: Macro variables referenced within a TEXT...ENDTEXT construct are expanded. Note that a field cannot be expanded, so you must first assign the field value to a memory variable then reference the memory variable as a macro variable within the TEXT...ENDTEXT. For example: USE Customer NEW myVar := Customer->CustName TEXT This is text with a macro &myVar ENDTEXT . Nested macros: The processing of macro variables and expressions in CA-Clipper permits nested macro definitions. For example, after assigning a macro variable to another macro variable, the original macro variable can be expanded resulting in the expansion of the second macro variable and evaluation of its contents: cOne = "&cTwo" // expand cTwo cTwo = "cThree" // yielding "cThree" cThree = "hello" // ? &cOne // Result: "hello"
Tag Archives: Code Blocks
A tale about Clipper
A tale about the origin of Clipper
There is a tale about the origin of CA-Clipper. Whether it is true or not, few people know, but “insiders” have said that it is not far from the truth. Here it is.
One day in a seafood restaurant in Malibu, California, an Ashton-Tate employee and a consultant friend were having lunch. They were expressing their annoyance at the fact that Ashton-Tate had not created a compiler for the dBase language.
The two thought that maybe they should have a go at starting up a new company to create the compiler. As the excitement grew and the ideas flew, the issue of a product name came up.
One of the two noticed a picture of a sailing ship on the napkin (after all this was a seafood restaurant). It was a clipper ship — a sleek, speedy, and elegant thing. That seemed to describe what they were trying to create.
What about the company name? The menu answered that question — the restaurant name was Nantucket Lighthouse.
And so Nantucket’s Clipper was born.
The consultant was Barry ReBell and the Ashton-Tate employee was Brian Russell.
Since that time there were four “seasonally” named versions of the compiler: Winter 85, Spring 86, Autumn 86, Summer 87. Very “California”…
These early versions clearly billed themselves as dBase compilers, with the Summer 87 version displaying “dBase III® compiler” on the floppy disks and documentation.
Many programmers using Clipper at the time were really “just” dBase programmers with a tool to create faster programs. So it was quite a shock to them when Clipper 5 was released. “What have they done to our language?”, they asked. Local variables? Code blocks? Tbrowse?
But there were also those of us who had strained against the limitations of the dBase language — the lack of modularity, the clumsiness, the vulnerability of public and private variables.
So we recognized that Clipper 5 was a turning point in the history of the Xbase language. No longer billed as a dBase compiler, Clipper became an “Application Development System”. A real language.
Well, maybe not as real as C, but getting there. In fact, many Clipper 5 concepts were borrowed from C and other languages. The increment operator (++
) and expression lists, for example, seem to have come from C, while code blocks may have been inspired by SmallTalk
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
This article borrowed by courtesy of author, from here.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Please look at here for continuation of this post.
Mere Clipper
It is a sad story, and it takes time for the world to really understand her story, especially her references to “The Book of Clipper”. What was Clipper? Was this what helped her maintain her sanity and her faith in God? What happened to the young girl? Her story spreads around the world, and a never-ending search continues for a copy of “The Book of Clipper”. Finally, the search ends in a little Russian town. Not a single person realizes that “The Book of Clipper” is a reference to the manual for the computer language that every single Russian speaks fluently, until someone finds a copy of the manual that Larry Heimendinger had left at the only Russian Clipper conference ever held – in 1992. It is dusty and worn, but it is the only book left that tells the true story of Clipper. Even though every programmer in Russia can speak Clipper, not a single one of them has seen a copy of “The Book of Clipper” because none had ever been sold. The software had been pirated, and then spread from disk to disk throughout the country while the story of Clipper passed from mouth to mouth. The Russians are the only civilized society that still has a programming language, so they offer it as a gift to the world, and the world becomes whole again, and the people rejoyce, and I come out of hiding – to write my final article about Clipper.
It’s a Wonderful Life
I like to imagine that I am the angel in the story “It’s a Wonderful Life” and that I have been called on by God to rescue a person who feels that his life has been lived in vain. In my rendition of the story, the desperate soul is not George Bailey but instead is Tom Rettig. Tom passed away about a year ago and I find myself haunted by him because I feel that I have never given back to him what he gave to me and the rest of the world. I often think back at what my life was like in the mid 80’s. After many successful years as an Electronics Engineer my life was just not working anymore. Thieves broke into my business office and stole my computers and my software (including the backups). I was struggling with a failing computer-accessories manufacturing business that had pushed me deep into debt, and then my wife decided to just leave one day and head for greener pastures. I thought she had been kidnapped because she disappeared without a trace.
Arlo Guthrie once wrote a song about “The Last Man”. He said “You think you’ve got it bad? Look at that guy?.” I WAS that guy.
Then, one day, in early 1986 I was struggling with a problem trying to get dBase-III to work properly on my new peer-to-peer network. I recall making a tech support call to the network developer and the person on the phone asked “Are you compiling with Clipper?”
This simple question, in retrospect, was equivalent to someone posting a huge sign “Except a man be born again, he cannot see the kingdom of God”. Clipper was my salvation. It allowed me to layeth down in green pastures and it restoreth my soul. So how did it come about that a person could be saved from the depths of depravity by a mere software product? We all have our stories of salvation, and they all take us down different paths but they all lead to the same place. My story in not unlike C.S. Lewis’ story in “Mere Christianity”, except the players are different. The Book of Clipper is not one story, but hundreds of stories all evolving from the “Platitudes of Vulcan”.
Tom Rettig entered the scene around 1986 and offered an add-on product to Clipper titled “Tom Rettig’s Library”. Tom was a well-liked, generous person who eventually offered his library into the public-domain. Some of us are old enough to remember him as Jeff, the small boy in the original “Lassie” series on television in the 50’s. I first met him at a user group in Southern California. After the meeting we went to a bar for a few beers and he sat and talked to us like we had all known him for years. He inspired us to do what he did, because he was just like us. The next day, I thought “If Tom Rettig can make a successful add-on product to Clipper, so can I”. I wasn’t the only person who had seen the light that night. Tom had broken new ground, had planted the first seeds, and from these seeds, an entire community of user-groups, programmers, applications, add-on products, books, magazines, et al, grew into maturity.
Two Steps Back
Have you ever heard anyone say “He’s so far behind he’s ahead”? By now, most of you have decided that you must move on to Windows and that there is no place for Clipper in your strategy. Many of you have already done so and are experimenting with products like VO, Delphi, VB, and Power-Builder or have created applications with these development environments. I am not writing this article to suggest that in any way, this was a bad choice. I have spent sufficient time with these products to come to the realization that Windows applications can be developed by travelling many different paths. What I am offering, however, is another perspective; one that frees us to open our minds to look at the future from a different view. Many of us have been so busy and so worried about constantly moving forward that we have forgotten how we got here in the first place, by the use of an enduring and powerful language – Clipper.
So you may be thinking “What is he talking about? Clipper is Dead!”. In the sense of a product, this may be true, but in the sense of a language, it is far from true. Let’s imagine that Chinese is packaged into a product named “Visual-Chinese” and this product includes a set of design-tools for creating quick-Chinese documents that can be easily integrated into our marketing documents. Soon we would find our business opened up to a new market of 1 billion people. The product becomes instantly successful and everyone love its and uses it – until, years later, when we find that our marketing documents are not delivering any sales. Why? Because the language had to be cut and trimmed to fit into the limitations of the software environment. It becomes ambiguous, arrogant and unwanted by the very people who inspired its development, so it dies and Visual-Chinese gets thrown away like every other Visual tool. Does this mean that the Chinese language dies with the product? No. Chinese is a language that will endure. It has lots of users; it is robust, and it is mature.
The key word is “language“. Development strategies should be built around the choice of a proper language, not just a product. Clipper is a language that endures. It cannot die. It has widespread use around the world and there are hundreds of thousands of Clipper legacy applications still doing mission- critical work. Unfortunately, because the word “Clipper” is owned by CA, and because CA has essentially abandoned Clipper, it cannot endure under the name Clipper, so it must endure under another name: that name is “Xbase”. Software developers try to treat languages like they own them, but they are only temporary custodians. This leads us to a discussion of the current state of the Xbase language. Xbase currently ( 1998 ) exists in 5 dialects:
- 1. dBase – A Windows-based Interpreter.
- 2. FoxPro – A Windows-based Interpreter.
- 3. CA-Clipper – A DOS-based Xbase compiler.
- 4. CA-VO – A 32-bit Windows-based Xbase compiler.
- 5. Xbase++ – A 32-bit Multi-Platform Compiler.
Xbase as dBase
dBase was the custodian of the Xbase language from around 1983 until about 1987. Unfortunately, it was an interpretive language so it never gained respectability as a true, robust language, however, it had much to offer the developer in ease-of-use and database design. dBase continues to be supported by Borland, simply because there is still money to be made in upgrades and conferences, but Borland has made it clear that they intend to make dBase programmers learn how to speak Pascal and eventually will phase Xbase out of their products.
Xbase as FoxPro
FoxPro took over as a co-custodian of the Xbase language in about 1987 and emerged around the same time as Clipper. FoxPro defeated dBase nearly overnight simply because it was faster, not because it delivered any new language concepts. FoxPro continues to be supported by Microsoft, simply because there is still money to be made in upgrades and conferences, but Microsoft has made it clear that they intend to make FoxPro programmers learn how to speak Visual Basic and eventually will phase Xbase out of their products.
Xbase as Clipper
Clipper was undoubtely the best custodian of the Xbase language from 1987 to 1996. Clipper introduced the Xbase compiler, the open-architecture concept of the extend system, code blocks, locals, statics, multi-dimensional arrays, the RDD layer, the preprocessor, and language extensions. Clipper was the first Xbase custodian to give Xbase respectability as a true programming language. Clipper maintained this respectability until around 1996 when CA released CA-Clipper 5.3. CA chose to treat Clipper as a “package” rather than a “language” and alienated nearly the entire Clipper community when they bundled a Windows-IDE and several third-party products into the package. This was when Clipper died.
Xbase as VO
Computer Associates planned for VO to take over as the custodian of the Xbase language by forcing the death of Clipper and dragging CA customers into a new kind of development environment that kind of looks like Clipper, in that it inherited much of the new Clipper extensions. Unfortunately, migration to VO became cumbersome due to too many incompatabilities, poor performance, poor reliability and a third-party community who could not get their products to work with VO. VO promised it would be easy to migrate existing Clipper applications to Windows but could not deliver on the promise. Working in VO is in no way similar to working in Clipper. Many Clipper developers find that using a third-party Windows library (like Five-Win or Clip-4-Win) with Clipper is a much easier migration path than VO.
…
Why Xbase?
Many of us wonder why Xbase has not been given more respectability as a “mainstream” language. If Xbase is so good, why are Borland and Microsoft phasing it out of their future products? I was watching a television program the other day about an analysis of automobile technology over the years. We often assume that the best technology is what endures over time and that it eventually rises to the top. This may be true in an ideal world, but in a capitalist society, it is usually market dog-fights that determine dominance. In this analysis, it was determined that steam technology could have produced cars just as good as internal combustion technology, but Henry Ford chose the latter. Bill Gates has chosen Basic, not because it is better, but because he owns it. He doesn’t own Xbase, and Bill cannot embrace something that he cannot control. Borland chose Pascal. Not because it is better, but becaused they own it.
Over the past 10 years, the success of the Xbase products has been due to the high degree of abstraction of the Xbase language, which makes it vastly simpler to acces and use operating system functions and resources. In addition, Xbase is more than just a specialized programming language, a database navigation language, or a user interface language – instead, it combines all of these roles, harmoniously integrating them with one another.
Xbase offers dynamic data types and is generally described as being highly “tolerant“. Taken together, these benefits have persuaded a steadily growing community of users and developers to rely upon it as a choice for implementing mission-critical and commercial PC-desktop applications. In fact, world-wide, more than one-third of all DOS-based commercial applications now in use were written in Xbase, with Clipper accounting for the major share.
…
Square Pegs and Round Holes
Most Windows programmers will tell you that you cannot take a standard Clipper application with @SAY..GETS, Menu Prompts, etc, and convert it to a Windows GUI program without a major change in the architecture and the functionality of the program. They claim that a text-based, modal design has too little in common with GUI-based, event-driven, non-modal design. They will tell you that it like trying to fit a square peg into a round hole. For years, I believed this because it made sense. I, like everyone else, wrote my Windows applications with a different structure than my Clipper applications. They were built around an event model rather than a procedural model and the code was tightly-bound rather than loosely-bound to the functional model. This always leaves me with an uneasy feeling because it forces me to write applications that are less modular and are platform specific. Microsoft, Borland, and CA each wants us to build applications their way. They want us to learn their programming tools, their methods, their plug-ins, their workshops, and their studios – not their language. Why? Because applications built around their environment will be harder to migrate to competitor’s products than applications built around a language.
So they make sure that the language is difficult and inaccessible, and that the application cannot be maintained or migrated to any other platform, other than platforms that they support. Programmers, however, have to survive in the real world and this requires platform flexibility. The reason why so many mission- critical DOS applications are still surviving in the real world is because each development platform supports DOS as a subset, so DOS has been, out of necessity, elevated to the status “platform independent”. I can run my Clipper applications under MS-DOS, PC-DOS, DR-DOS, OS/2, Windows 3.1, Windows 95, Citrix- Winframe, MULTI-DOS, Windows NT and Novell-DOS. I can run my Delphi applications only under 32-bit Windows. Is this a step forward?
…
Cocoon
In my dream, the “Ghost of Xbase Future” led me through the Land of Clipper and how it might look like up through the year 2035. I couldn’t hold back my emotions as I witnessed the data meltdown and the termination of millions of programmers. I asked him “Spirit – is this a vision of how things MUST be or how things COULD be?” He never answered me. I woke up from my dream and ran to the mirror. I was relieved to see that I wasn’t 91 years old but was still a young man. I exclaimed “There’s still time!” I bolted to the window, looked out, and saw that The Land of Clipper looks different than it did yesterday. The paths are 32-bits wide and they lead everywhere, yet they look familiar and something tells me that there is nothing to fear at the end of these paths. Then I realized that I had not been dreaming and that Clipper had not really died at all but had been in a cocoon, waiting to metomorphose into a butterfly, one with big X’s on it’s wings. The butterfly is beautiful and it attracts the attention of people like Dirk Lesko (author of Funcky), of Jud Cole (author of Blinker), of Dave Kuechler (author of Comix), and others who once frolicked in the land of Clipper.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Note: This article is a summary ( by courtesy of author) original is here.