dCRUNCH for Program Speed (PC Magazine Vol 5 No 13 Power User) In both "Pseudo Compiler for dBASE II" (PC Mag Vol 5 No 5 Power User) and "dBASE Speed Tips" (PC Mag Vol 5 No 1 Power User), the point is made that dBASE programs will execute faster if leading and trailing spaces, blank lines, and "*" lines are stripped out and if everything (except quoted text) is capitalized. (See the file DB3MISC.TXT for the articles cited here.) To facilitate the necessary file preparation, dCRUNCH.BAT and dSTRIP.COM will convert a 64K command file in under 6 seconds. Before running programs through the DOS filter, edit out any single apostrophes inside NOTE or TEXT/ENDTEXT statements, since capitalization is based on pairs of apostrophes, double quote, or brackets. Note also that everything inside a TEXT/ENDTEXT statement will be capitalized and left-justified unless you first enclose it in quotes, then edit out the quotes later. The syntax for the command is: DCRUNCH [d:][path][filename] and you should omit the .PRG filename extension. dBASE's interpreter is its weakest (slowest) link. When a command is issued, the interpreter 1) parses the full command line; 2) discards leading spaces; 3) indexes to the first space to identify the verb; 4) truncates the string if it's longer than four characters; 5) converts it to uppercase; 6) searches its lookup table of initial verbs; and, 7) gets down to business. If you write a long NOTE or "*" comment, the interpreter looks at every byte, savors a delicate sample, then spits it out. The same applies when you add a comment after ENDIF or ENDDO, or when you indent command lines for legibility. Take, for example, this simple iterative loop: variable_x=0 DO WHILE variable_x<1000 variable_x=variable_x+1 *This is a long comment line *explaining what's going on ENDDO dCRUNCH shortens processing of this loop over 25 percent -- from 58 to 42 seconds. The biggest offender is the"*" line -- 13 seconds; a long comment tacked on to the ENDDO will have the same effect. Shortening "variable_x" to "x" shaves another 6 seconds. There is no measurable difference is one blank line is added, but a large overhead begins to accumulate with each additional blank line. Five blank lines increase execution time of 1,000 loops by 11 seconds. dCRUNCH's side effects are substantial. A program that is all- capitalized and left-justified without comments or mnemonic variable names is awful to read and a nightmare to modify 6 months later. And, in most applications, a few extra milliseconds inside a loop is the least of your problems. But if you need maximum speed inside an intensive loop -- like passing each record in a file -- dCRUNCH is just the ticket. - - - - - dCRUNCH.BAT: ECHO OFF REM dCRUNCH.BAT Speeds dBASE routines. Calls dSTRIP.COM IF %1/==/ GOTO noparm IF NOT EXIST dstrip.com GOTO nocom IF EXIST %1.prg GOTO strip ECHO ----- ECHO File %1.PRG not found IF EXIST %1 ECHO Please specify the file without .PRG extension GOTO noparm :strip IF NOT EXIST %1.prk GOTO work ECHO ----- ECHO A back-up file %1.PRK already exists and will be overwritten. ECHO Hit CTRL-BREAK followed by Y to interrupt or ... PAUSE DEL %1.prg :work ECHO Streamlining %1.prg. Original version is saved as %1.prk REN %1.prg %1.prk dstrip <%1.prk >%1.prg GOTO end :noparm ECHO SYNTAX: DCRUNCH [d:][path][filename] (omit ".prg" extension) GOTO end :nocom ECHO File DSTRIP.COM not found. :end - - - - - DSTRIP.ASM (to create DSTRIP.COM): ; DSTRIP - DOS filter to remove leading and trailing blanks, blank ; lines and comment lines from dBASE command files, and to ; capitalize text not in quotation marks. ; comseg segment para public 'code' assume cs:comseg,ds:comseg,es:comseg,ss:comseg org 100h start proc far cld mov bl,00000001b ;the bits in the BL register will hold ;the following information when set to 1: ;0-bit only tabs and blanks encountered ; in current line ;1-bit a '*' encountered as first ; character of line ;4-bit char inside 'single' quotes ;5-bit char inside "double" quotes ;6-bit last char was linefeed ;7-bit last char in *-line was a ';' xor dx,dx ;DX will count blanks/tabs after a char load: push bx ;save registers and push dx mov dx,offset data ;read into memory mov cx,64000 ;64K bytes xor bx,bx ;from standard input mov ah,3fh ;with DOS function call int 21h pop dx ;restore registers pop bx or ax,ax ;AX has number of bytes read; test for 0 jnz load0 jmp done load0: mov cx,ax ;move count into CX mov si,offset data ;and position index registers for mov di,offset data ;a string move scan0: lodsb ;fetch a byte into AL cmp al,26 ;end of file? jz store ;if so, store and get out test bl,01000000b ;LF on previous fetch? jz next ;if not, skip or bl,1 ;set beginning of line bit and bl,10111111b ;and reset the LF bit test bl,10000000b ;a ';' at end of line? jnz next0 ;if yes, skip and bl,11111101b ;otherwise reset '*'-bit next0: and bl,01111111b ;reset ';'-bit next: cmp al,59 ;a ';'? jnz next1 ;if not, skip or bl,10000000b ;set ';'-bit jmp short next5 ;and do loop routine next1: cmp al,32 ;blank? jz count ;if yes, check whether to count it cmp al,09 ;tab? jnz next2 ;if not, skip count count: test bl,11b ;are we at beginning of line or in a '*'-line? jnz loop ;if yes, loop and omit inc dx ;otherwise count the blank/tab jmp short store ;and store it next2: cmp al,13 ;CR? jz out ;if yes go to end of line routine next3: cmp al,10 ;LF? jnz next4 ;if not, go on checking or bl,01000000b ;set end of line bit jmp short out ;and go to end of line routine next4: test bl,1 ;have we seen any nonblank/tab char before? jz next6 ;if yes, ignore the next step cmp al,42 ;a '*'? jnz next5 ;if not, skip or bl,10b ;otherwise set the '*'-bit next5: and bl,11111110b ;and in either case we have nonblank/tab char next6: xor dx,dx ;set blank/tab count to 0 out: test bl,11b ;are we at beginning of line or in a '*'-line? jnz loop ;if so, ignore (includes CR/LF of blank lines) sub di,dx ;DX is non-zero only if we encountered a CR xor dx,dx ;reset DX to 0 and bl,01111111b ;reset ';'-bit caps0: jmp short caps ;capitalize store: stosb ;store char loop: cmp al,26 ;test for end of file loopnz scan0 ;and loop for next fetch push ax ;save registers push bx push dx mov dx,offset data ;compute the numbers of bytes stored mov cx,di sub cx,dx ;in CX, and mov bx,01 ;write to standard output mov ah,40h ;with DOS function call int 21h pop dx pop bx pop ax cmp al,26 ;end of file? jz done jmp load ;if not, read another 64K bytes done: int 20h ;end program caps: cmp al,39 ;single quote? jnz quot ;if not, check double quote test bl,100000b ;is double quote bit set? jnz store ;if yes, ignore xor bl,010000b ;(re-)set single quote bit jmp short store quot: cmp al,34 ;double quote? jnz caps01 ;if not, skip xor bl,00100000b ;(re-)set double-quote bit jmp short store caps01: test bl,00110000b ;any quote-bits set? jnz store ;if so, don't capitalize caps1: cmp al,97 ;below 'a'? jb store ;if so, leave it alone caps2: cmp al,122 ;above 'z'? ja store ;if so, don't change caps3: and al,5fh ;otherwise capitalize out2: jmp short store start endp data: comseg ends end start - - - - - You can use DEBUG to create DSTRIP.COM by issuing the command: DEBUG < DSTRIP.INP with the following. DEBUG will use DSTRIP.INP as its input to create the .COM file. N DSTRIP.COM A CLD MOV BL,01 XOR DX,DX PUSH BX PUSH DX MOV DX,01CE MOV CX,FA00 XOR BX,BX MOV AH,3F INT 21 POP DX POP BX OR AX,AX JNZ 011C JMP 01A4 MOV CX,AX MOV SI,01CE MOV DI,01CE LODSB CMP AL,1A JZ 0184 TEST BL,40 JZ 013F OR BL,01 AND BL,BF TEST BL,80 JNZ 013C AND BL,FD AND BL,7F CMP AL,3B JNZ 0148 OR BL,80 JMP 0171 CMP AL,20 JZ 0150 CMP AL,09 JNZ 0158 TEST BL,03 JNZ 0185 INC DX JMP 0184 CMP AL,0D JZ 0176 CMP AL,0A JNZ 0165 OR BL,40 JMP 0176 TEST BL,01 JZ 0174 CMP AL,2A JNZ 0171 OR BL,02 AND BL,FE XOR DX,DX TEST BL,03 JNZ 0185 SUB DI,DX XOR DX,DX AND BL,7F JMP 01A6 STOSB CMP AL,1A LOOPNZ 0124 PUSH AX PUSH BX PUSH DX MOV DX,01CE MOV CX,DI SUB CX,DX MOV BX,0001 MOV AH,40 INT 21 POP DX POP BX POP AX CMP AL,1A JZ 01A4 JMP 0105 INT 20 CMP AL,27 JNZ 01B4 TEST BL,20 JNZ 0184 XOR BL,10 JMP 0184 CMP AL,22 JNZ 01BD XOR BL,20 JMP 0184 TEST BL,30 JNZ 0184 CMP AL,61 JB 0184 CMP AL,7A JA 0184 AND AL,5F JMP 0184 RCX 0CE W Q