Copyright 1991-2016 by Kevin G. Barkes All rights reserved. This article may be duplicated or redistributed provided no alterations of any kind are made to this file. This edition of DCL Dialogue is sponsored by Networking Dynamics, developers and marketers of productivity software for OpenVMS systems. Contact our website www.networkingdynamics.com to download free demos of our software and see how you will save time, money and raise productivity! Be sure to mention DCL Dialogue! DCL DIALOGUE Originally published September, 1991 Compiled DCL By Kevin G. Barkes For the past few months I've been playing with a field test version of the "holy grail" of command procedure afficianados: a DCL compiler. Actually, it's not a true compiler. Such a feat is well nigh impossible because of DCL's iterative substitution, runtime evaluation and other interpretative capabilities. What the soon-to-be-released software package from Channel Islands Software actually does is described quite well by the product's name: DCL to Fortran Precompiler, or DCP for short. SE HABLA DCL? DCP is a translator that reads in DCL command procedure files and outputs Fortran source code. The Fortran source is then compiled and linked, generating an executable image (.EXE) file. The DCP precompiler is licensed on a per-cpu basis, but the code it generates can be used freely on other systems. While you're admonished only to process totally debugged DCL command files, DCP performs translations admirably well. This is no mean feat, because the DCL interpreter is very loose in its enforcement of command syntax. DCP will point out "questionable" DCL code during processing, serving as a quasi-DCL debugger. Why generate Fortran code? Frank Noell, Channel Islands' vice president and author of DCP, explains it was chosen because "it is available on more VAXes than any other language, is very efficient, and has a very effective optimizer, as well as being one of the least expensive compilers available [from DEC]." To insure maximum compatibility, the DCP-generated Fortran code only uses routines contained within VMS system services and the supplied DCP object library. The downside to this approach is that DCP must execute most external DCL commands by spawning subprocesses to run the images. DCP tries to group commands requiring SPAWNs to reduce image activation time and improve performance. SPEED AND SECURITY DCP offers two primary advantages: security and speed. "Some functions that are performed by DCL [command files] require privilege, which must be granted directly to a user," Frank noted. "A compiled program," such as those generated by DCP, "can be installed with whatever privileges are required, and they will remain in effect only during the execution of the program. This also holds true when a program is executed from an installed [DCP] program by spawning." Another bonus is that the typical user cannot TYPE or change the code contained within an .EXE file, providing additional security. As for speed, DCL procedures "compiled" by DCP will run from two to ten times faster than .COM files executed under the control of the command interpreter. Actual execution speed depends on several factors, the most important of which is the number of external DCL commands which the DCP Fortran program must execute by subprocess spawning. Figure 1 is a straightforward DCL command procedure which extracts name fields from a 1,305 line data file and writes a reformatted name list to another file. Figure 2 shows the required steps to run the procedure through DCP, compile the Fortran source and link the resultant object file. Our 21 line .COM file produced 103 lines of active Fortran code from DCP's output, a portion of which is shown in Figure 3. Figure 4 displays the results of running the command file; Figure 5 shows what happens when the DCP-generated program is executed. Since the procedure was written to avoid using external DCL commands, the DCP Fortran program contains only native Fortran and VMS system service calls, with no SPAWNs to execute other DCL programs. As the results show, the DCP code is more than 240% faster than the DCL command file. NO FREE LUNCH As nifty as DCP is, it's important not to be blinded to its limitations. No, you can't run VMSINTAL or AUTOGEN through DCP. For that matter, you'll probably have to tweak your LOGIN.COM file to get it to run properly. Channel Islands Software goes to great lengths to emphasize that DCP isn't a "magic bullet" that will mystically convert your .COMs to .EXEs with a few simple keystrokes. Restrictions are clearly documented, and a thorough workarounds section offers useful tips on command file recoding. Frankly, DCP isn't for everyone. You should have a good grounding in DCL and some Fortran knowledge wouldn't be too bad, either. Still, a Fortran ignoramus like myself was able to run and compile translated .COMs without even bothering to look at the DCP-generated source code. As long as you don't have unrealistic expectations, DCP will provide you with a way to secure and accelerate critical portions of your DCL command files. I discovered that it was frequently more effective to break down a large .COM file into "interpretive" and "non-interpretive" components, running the non-interpretive stuff through DCP and leaving the fancy symbol substitution and other interactively-oriented code in native DCL. It also served as a useful exercise in efficient DCL coding. For more information about DCP, you can write to Channel Islands Software, P.O. Box 30492, Santa Barbara, CA 93130. Tell Frank I sent you. ****************************** Kevin G. Barkes is an aging independent consultant who: reminds us that this month marks the anniversary of the original network broadcast of Star Trek, which he remembers watching on September 8, 1966; shares a September 11 birthdate with Lola Falana and Ferdinand Marcos; and recalls when a 750 with 4 megabytes of memory was hot stuff. Kevin publishes the KGB Report newsletter, operates the www.kgbreport.com website, lurks on comp.os.vms, and can be reached at kgbarkes@gmail.com. ************************** FIGURE 1: $ OPEN/READ INFILE RAW.DAT $ OPEN/WRITE OUTFILE LIST.DAT $ START = F$GETJPI("","CPUTIM") $ COUNT = 0 $ LOOP: $ READ/END=DONE INFILE LINE $ COUNT = COUNT + 1 $ LASTNAME = F$EDIT(F$EXTRACT(0,20,LINE),"TRIM") $ FIRSTNAME = F$EDIT(F$EXTRACT(20,15,LINE),"TRIM") $ MIDDLE = F$EDIT(F$EXTRACT(35,1,LINE),"TRIM") $ IF MIDDLE .NES. "" THEN MIDDLE = ", "+MIDDLE+"." $ WRITE OUTFILE LASTNAME+", "+FIRSTNAME+MIDDLE $ GOTO LOOP $ DONE: $ CLOSE INFILE $ CLOSE OUTFILE $ FINISH = F$GETJPI("","CPUTIM") $ TOTAL = FINISH - START $ WRITE SYS$OUTPUT "Records read/written: ",COUNT $ WRITE SYS$OUTPUT "Total time (milliseconds): ",TOTAL $ EXIT ******************************************** FIGURE 2: $ dcp list DCL to FORTRAN Precompiler - Version 1.D (c) Copyright by Channel Islands Software, Inc. All Rights Reserved %DCPRECOMP-I-CMDPROC, processing LIST.COM %DCPRECOMP-I-RECPROC, 21 records processed, pass 1 %DCPRECOMP-I-RECPROC, 21 records processed, pass 2 %DCPRECOMP-I-FINAL, generating final FORTRAN program 136 lines written to LIST.FOR $ fortran list $ link list,sys$library:dcprecomp/lib/notrace ******************************************** FIGURE 3: PROGRAM LIST IMPLICIT NONE C INTEGER*4 DCP$$IOS,DCP$$RET,DCP$$ZERO/0/ CHARACTER*1 DCP$$NULL INTEGER*4 COUNT INTEGER*4 DCP$$001_LEN . . . C =============================== CODE ================================= . . . C $ OPEN/READ INFILE RAW.DAT 00010 OPEN (UNIT=21,STATUS='OLD',FORM='FORMATTED',FILE='RAW'//'.DAT') !025 C $ OPEN/WRITE OUTFILE LIST.DAT 00020 OPEN (UNIT=22,STATUS='NEW',FORM='FORMATTED',USEROPEN=DCP$$SEQ_OUTP 1UT,RECORDTYPE='VARIABLE',FILE='LIST'//'.DAT') !025 C $ START = F$GETJPI("","CPUTIM") 00030 START=F$GETJPI_I('!','"CPUTIM"') !002 IF (IBITS(DCP$$STATUS,0,3) .GT. 1 .AND. .NOT. IBITS(DCP$$STATUS,0, 11)) GOTO 90000 ! (on error) !042 . . . C $ WRITE SYS$OUTPUT "Records read/written: ",COUNT 00190 DCP$$STR_004 = F$STRING(COUNT,DCP$$008_LEN) !032 TYPE *, 'Records read/written: '//DCP$$STR_004(1:DCP$$008_LEN) !007 C $ WRITE SYS$OUTPUT "Total time (milliseconds): ",TOTAL 00200 DCP$$STR_005 = F$STRING(TOTAL,DCP$$009_LEN) !032 TYPE *, 'Total time (milliseconds): '//DCP$$STR_005(1:DCP$$009_LEN 1) !007 C $ EXIT 00210 GO TO 90000 !022 . . . ******************************************** FIGURE 4: @list Records read/written: 1305 Total time (milliseconds): 5216 ******************************************** FIGURE 5: $ run list Records read/written: 1305 Total time (milliseconds): 2166