home *** CD-ROM | disk | FTP | other *** search
/ Power-Programmierung / CD1.mdf / magazine / progjour / 1991 / 06 / alibtool / order.asm < prev    next >
Assembly Source File  |  1991-08-23  |  14KB  |  701 lines

  1.     title    order - resequence procedure labels
  2.     include    asm.inc
  3.  
  4.     public    main
  5.  
  6. ;
  7. ; Assemble with /ML switch:    C>masm order/ml;
  8. ;                C>link order;
  9. ;
  10. ; (C) Soft Advances 1991, All Rights Reserved
  11.  
  12. PROC_LINE_MAX        equ    250
  13. DOUBLE_CASE_BITS    equ    2020h
  14.  
  15.  
  16.     .data
  17.     extb    ertx_file_too_big
  18.     extw    dgroup_segment
  19.  
  20.  
  21. write_output_flag    db    0    ; set this flag if input file changes
  22.  
  23. proc_text        db    'proc'
  24. endp_text        db    'endp'
  25. bak_text        db    'bak'
  26.  
  27. ertx_endp_missing    db    'ENDP missing',0
  28. ertx_output_file    db    'Error creating, writing, or closing output',0
  29. ertx_rename        db    'Rename failed',0
  30.  
  31. help_text        db    'order file.asm',10
  32.     db 'Resequences procedure labels in file.asm.  Labels must be',10
  33.     db 'of the form "n$" or "ABCn" (e.g. 1$, 32$, abc1, foo23).',10
  34.     db 'Before updating file.asm, order renames file.asm to file.bak.',10
  35.     db 'Version 1.2  8-21-91  by John Otken',0
  36.  
  37. no_update_text        db    'sequence OK, nothing written',0
  38. resequenced_text    db    ' resequenced',0
  39.  
  40.     .data?
  41.     extd    argv
  42.     extw    argc
  43.  
  44. label_count        dw    ?    ; number of labels in procedure body
  45. label_table        dw    PROC_LINE_MAX dup(?)
  46.  
  47. output_bucket        dd    ?    ; output buffer pointer
  48. output_bc        dw    ?
  49.  
  50. proc_initials        db    ?,?,?,?    ; first 3 characters of local label
  51.  
  52. bak_filename        db    FILENAME_MAX dup(?)
  53.  
  54.  
  55.     .code
  56.  extn isalpha_,isdigit,isalpha,strskp_white,isalnum,startup,open_output_file
  57.  extn strskp_white,strskp_line,ms_dos,read_entire_file
  58.  extn malloc,puts_dgroup,putchar,set_strerror,perror,remove,rename
  59.  extn close_file_cf,write_to_file
  60.  
  61.  
  62. ;;    atoi skip
  63. ;
  64. ;    entry    DS:SI    ascii digits
  65. ;    exit    AX    binary value
  66. ;        SI    updated to digit string delimiter
  67. ;        Cf    if bad number
  68. ;
  69. atoi_update proc
  70.     call    strskp_white
  71.     call    isdigit
  72.     jne    ati4            ; if bad or negative number
  73.  
  74. ati1:    push    dx            ; process first digit
  75.     sub    al,'0'
  76.     cbw
  77.     mov    dx,ax
  78.     inc    si
  79.  
  80. ati2:    mov    al,[si]            ; process each digit
  81.     call    isdigit
  82.     jne    ati3            ;  if end of digits
  83.  
  84.     add    dx,dx            ;  multiply by ten
  85.     mov    ax,dx
  86.     add    dx,dx
  87.     add    dx,dx
  88.     add    dx,ax
  89.  
  90.     lodsb                ;  sum new digit
  91.     sub    al,'0'
  92.     cbw
  93.     add    dx,ax
  94.     jmp    ati2
  95.  
  96. ati3:    clc
  97.     mov    ax,dx
  98.     pop    dx
  99.     ret
  100.  
  101. ati4:    cmp    al,'-'            ; here for possible negative number
  102.     jne    ati5            ;  if bad number
  103.  
  104.     inc    si            ;  else probable negative number
  105.     mov    al,[si]
  106.     call    isdigit
  107.     je    ati5            ;  if bad number
  108.  
  109.     call    ati1            ; parse digits
  110.     neg    ax
  111.     clc
  112.     ret
  113.  
  114. ati5:    stc
  115.     ret
  116. atoi_update endp
  117.  
  118.  
  119. ;;    atoi special
  120. ;
  121. ;    entry    DS:SI    ascii digits
  122. ;    exit    AX    binary value
  123. ;        SI    updated to digit string delimiter
  124. ;        Cf    if bad number or leading zeros
  125. ;
  126. atoi_special proc
  127.     cmp    bptr [si],'0'        ; check for leading zero in digit
  128.     jne    atoi_update        ;  if no leading zero
  129.  
  130.     mov    al,[si+1]        ;  else leading 0, check for lone 0
  131.     call    isdigit
  132.     jne    atoi_update        ;  if lone zero, parse it
  133.     stc
  134.     ret
  135. atoi_special endp
  136.  
  137.  
  138. ;;    check label sequence
  139. ;
  140. ;    exit    Cf    if labels out of sequence
  141. ;    uses    AX,BX
  142. ;
  143. check_label_sequence proc
  144.     mov    ax,0
  145.     lea    bx,label_table
  146.  
  147. cll1:    cmp    ax,label_count[bp]
  148.     je    cll2            ; if all labels OK (Cf=0)
  149.     inc    ax
  150.     cmp    ax,ss:[bx]
  151.     lea    bx,[bx+2]
  152.     je    cll1            ; if label correctly sequenced
  153.     stc                ; else indicate bad sequencing
  154. cll2:    ret
  155. check_label_sequence endp
  156.  
  157.  
  158. ;;    convert label index
  159. ;
  160. ;    entry    AX    old label index
  161. ;    exit    AX    new label index
  162. ;        Cf    if bad index
  163. ;
  164. convert_label_index proc
  165.     pushm    cx,di,es
  166.     mov    es,dgroup_segment[bp]    ; search table for old label index
  167.     lea    di,label_table
  168.     mov    cx,label_count[bp]
  169.     repne    scasw
  170.     stc
  171.     jne    cli1            ;  if not found, return error
  172.  
  173.     mov    ax,di            ;  else return correct index
  174.     sub    ax,offset label_table
  175.     shr    ax,1
  176.     clc
  177. cli1:    popm    es,di,cx
  178.     ret
  179. convert_label_index endp
  180.  
  181.  
  182. ;;    count proc lines
  183. ;
  184. ;    entry    DS:SI    procedure text
  185. ;        DX    end of proc offset
  186. ;    exit    CX    number of lines
  187. ;    uses    AX
  188. ;
  189. count_proc_lines proc
  190.     push    si
  191.     mov    cx,0
  192.  
  193. cpl1:    cmp    si,dx
  194.     jae    cpl2            ; if end of procedure
  195.     call    strskp_line
  196.     inc    cx
  197.     jmp    cpl1
  198.  
  199. cpl2:    pop    si
  200.     ret
  201. count_proc_lines endp
  202.  
  203.  
  204. ;;    extract label number
  205. ;
  206. ;    entry    DS:SI    local label with colon delimiter
  207. ;    exit    AX    label #
  208. ;        Cf    if unsupported or non-local label
  209. ;
  210. extract_label_number proc
  211.     push    si
  212.     lodsb
  213.     call    isdigit
  214.     je    eln1            ; if OPTASM local label (1$:)
  215.     cmp    al,proc_initials[bp]
  216.     jne    eln3            ; if bad label
  217.     lodsb
  218.     cmp    al,proc_initials[bp+1]
  219.     jne    eln3            ; if bad label
  220.     lodsb
  221.     cmp    al,proc_initials[bp+2]
  222.     jne    eln3            ; if bad label
  223.  
  224.     call    atoi_special
  225.     jc    eln3            ; if bad label index
  226.     jmp    eln2
  227.  
  228. eln1:    dec    si            ; here for OPTASM labels (1$:)
  229.     call    atoi_special
  230.     jc    eln3
  231.  
  232.     cmp    bptr [si],'$'
  233.     jne    eln3            ;  if dollar sign suffix missing
  234.     inc    si
  235.  
  236. eln2:    cmp    bptr [si],':'
  237.     je    eln4            ;  if near label colon OK (Cf=0)
  238. eln3:    stc                ;  else set error flag
  239.  
  240. eln4:    pop    si
  241.     ret
  242. extract_label_number endp
  243.  
  244.  
  245. ;;    find local labels
  246. ;
  247. ;    entry    DS:SI    procedure text
  248. ;        CX    nonzero line count
  249. ;    exit    Cf    if unable to process procedure
  250. ;    uses    AX,BX
  251. ;
  252. find_local_labels proc
  253.     pushm    cx,si
  254.     mov    label_count[bp],0
  255.     lea    bx,label_table[bp]
  256.  
  257. fll1:    mov    al,[si]            ; process procedure line
  258.     cmp    al,SPACE_CHAR
  259.     jbe    fll2            ;  if no label on this line
  260.     cmp    al,';'
  261.     je    fll2            ;  if comment then not label
  262.  
  263.     call    extract_label_number
  264.     jc    fll3            ;  if unknown label format
  265.  
  266.     mov    ss:[bx],ax        ; record label index in label_table
  267.     add    bx,2
  268.     inc    label_count[bp]
  269.  
  270. fll2:    call    strskp_line        ; advance to next line
  271.     loop    fll1
  272.     clc
  273.  
  274. fll3:    popm    si,cx
  275.     ret
  276. find_local_labels endp
  277.  
  278.  
  279. ;;    find proc endp
  280. ;
  281. ;    entry    DS:SI    text ptr
  282. ;        SS:BX    points to either "proc" or "endp"
  283. ;    exit    SI    points to line after proc or endp
  284. ;        DX    points to start of proc or endp line
  285. ;        Cf    if end of file
  286. ;    uses    AX
  287. ;
  288. find_proc_endp proc
  289.     jmp    fpe2
  290. fpe1:    call    strskp_line        ; advance to next source line
  291.  
  292. fpe2:    mov    al,[si]            ; check start of line for proc name
  293.     cmp    al,NULL_CHAR
  294.     je    fpe4            ;  if end of file
  295.     call    isalpha_
  296.     jne    fpe1            ;  if not name (must start w/ letter)
  297.  
  298.     mov    dx,si            ; skip to token following name
  299. fpe3:    lodsb
  300.     call    isalpha_
  301.     je    fpe3
  302.     dec    si
  303.     call    strskp_white
  304.  
  305.     mov    ax,[si]            ; check for PROC or ENDP tokens
  306.     or    ax,DOUBLE_CASE_BITS
  307.     cmp    ax,ss:[bx]
  308.     jne    fpe1            ;  if not PROC or ENDP
  309.     mov    ax,[si+2]
  310.     or    ax,DOUBLE_CASE_BITS
  311.     cmp    ax,ss:[bx+2]
  312.     jne    fpe1            ;  if not PROC or ENDP
  313.     mov    al,[si+4]
  314.     call    isalpha_
  315.     je    fpe1            ;  if not PROC or ENDP
  316.     call    strskp_line
  317.  
  318. fpe4:    add    al,-1            ; (set Cf if AL==0)
  319.     cmc
  320.     ret
  321. find_proc_endp endp
  322.  
  323.  
  324. ;;    get proc initials
  325. ;
  326. ;    entry    DS:SI    procedure body
  327. ;        CX    line count
  328. ;    exit    Cf    if unsupported label syntax
  329. ;    uses    AX
  330. ;
  331. get_proc_initials proc
  332.     pushm    cx,si
  333. gpi1:    mov    al,[si]            ; search for "3 initial" local label
  334.     call    isalpha
  335.     je    gpi2            ;  if found (maybe)
  336.     call    strskp_line
  337.     loop    gpi1
  338.     clc                ; no 3 initial label found (not error)
  339.     jmp    gpi4
  340.  
  341. gpi2:    mov    proc_initials[bp],al    ; save initials 1, 2, and 3
  342.  
  343.     mov    al,[si+1]
  344.     call    isalpha
  345.     jne    gpi3            ;  if non-alpha, is not local label
  346.     mov    proc_initials[bp+1],al
  347.  
  348.     mov    al,[si+2]
  349.     call    isalpha
  350.     jne    gpi3            ;  if non-alpha, is not local label
  351.     mov    proc_initials[bp+2],al
  352.  
  353.     mov    al,[si+3]
  354.     call    isdigit
  355.     je    gpi5            ;  if good "3 initial" local label
  356.  
  357. gpi3:    stc
  358. gpi4:    mov    wptr proc_initials[bp],0
  359.     mov    bptr proc_initials[bp+2],0
  360.  
  361. gpi5:    popm    si,cx
  362.     ret
  363. get_proc_initials endp
  364.  
  365.  
  366. ;;    help
  367. ;
  368. help    proc
  369.     lea    ax,help_text
  370.     call    puts_dgroup
  371.     ret
  372. help    endp
  373.  
  374.  
  375. ;;    itoa decimal
  376. ;
  377. ;    entry    AX    number
  378. ;        ES:DI    destination
  379. ;    exit    DI    updated (points to delimiting 0)
  380. ;    uses    AX
  381. ;
  382. itoa_decimal proc
  383.     cmp    ax,0
  384.     jge    ita1            ; if positive
  385.     mov    bptr es:[di],'-'    ; else "stosb" minus sign
  386.     inc    di
  387.     neg    ax
  388.  
  389. ita1:    pushm    cx,dx
  390.     mov    cx,10
  391.     mov    dx,-1            ; push sentinal
  392. ita2:    push    dx
  393.     mov    dx,0
  394.     div    cx            ; divide digits
  395.     cmp    ax,0
  396.     jne    ita2
  397.     inc    dx
  398. ita3:    xchg    ax,dx            ; write digits
  399.     add    al,'0'-1
  400.     stosb
  401.     pop    dx
  402.     inc    dx
  403.     jnz    ita3            ;  if not sentinal
  404.     mov    es:[di],dl        ; write delimiting 0
  405.     popm    dx,cx
  406.     ret
  407. itoa_decimal endp
  408.  
  409.  
  410. ;;    main
  411. ;
  412. main    proc
  413.     cmp    argc[bp],1
  414.     jbe    help            ;  if no arguments - exit
  415.  
  416.     lds    si,argv[bp]
  417.     mov    si,[si+2]
  418.  
  419.     call    read_entire_file
  420.     jc    mai4            ;  if file not found or too big
  421.     call    malloc_output_bucket
  422.     jc    mai4            ;  if not enough memory
  423.  
  424. mai1:    mov    cx,si            ; find start of next procedure
  425.     lea    bx,proc_text
  426.     call    find_proc_endp
  427.     jc    mai2            ;  if end of file
  428.  
  429.     xchg    cx,si            ; output source up to procedure
  430.     sub    cx,si
  431.     rep    movsb
  432.  
  433.     mov    cx,si            ; find end of procedure
  434.     lea    bx,endp_text
  435.     call    find_proc_endp
  436.     jc    mai3            ;  if endp missing error
  437.  
  438.     mov    si,cx            ; count lines in procedure body
  439.     call    count_proc_lines
  440.     jcxz    mai1            ;  if empty proc, ignore it
  441.     cmp    cx,PROC_LINE_MAX
  442.     ja    mai1            ;  if procedure too long, ignore it
  443.  
  444.     call    get_proc_initials
  445.     jc    mai1            ;  if unsupported local label syntax
  446.  
  447.     call    find_local_labels
  448.     jc    mai1            ;  if unsupported label syntax
  449.  
  450.     call    check_label_sequence
  451.     jnc    mai1            ;  if label sequence OK
  452.  
  453.     call    resequence_proc_labels
  454.  
  455.     mov    write_output_flag[bp],-1
  456.     call    putchar_proc_name
  457.     jmp    mai1
  458.  
  459. mai2:    xchg    cx,si            ; output source up to procedure
  460.     sub    cx,si
  461.     rep    movsb
  462.     sub    di,wptr output_bucket[bp] ; save output byte count
  463.     mov    output_bc[bp],di
  464.  
  465.     call    update_asm_source
  466.     jc    mai4            ;  if any errors updating .asm file
  467.  
  468.     mov    al,EXIT_SUCCESS
  469.     ret
  470.  
  471. mai3:    lea    ax,ertx_endp_missing
  472.     call    set_strerror
  473. mai4:    mov    si,NULL_POINTER
  474.     call    perror
  475.     mov    al,EXIT_FAILURE
  476.     ret
  477. main    endp
  478.  
  479.  
  480. ;;    malloc output bucket
  481. ;
  482. ;    entry    CX    file byte count
  483. ;    exit    ES:DI    output bucket
  484. ;        Cf    if file too big or not enough memory
  485. ;    uses    AX,CX
  486. ;
  487. malloc_output_bucket proc
  488.     add    cx,1024            ; allocate oversized output bucket
  489.     jc    mob2            ;  if file too big
  490.     call    malloc
  491.     jc    mob1            ;  if not enough memory
  492.  
  493.     mov    wptr output_bucket[bp],di
  494.     mov    wptr output_bucket[bp+2],es
  495. mob1:    ret
  496.  
  497. mob2:    lea    ax,ertx_file_too_big
  498.     call    set_strerror
  499.     ret
  500. malloc_output_bucket endp
  501.  
  502.  
  503. ;;    putchar proc name
  504. ;
  505. ;    entry    DS:SI    points to endp line
  506. ;    uses    AX
  507. ;
  508. putchar_proc_name proc
  509.     push    si            ; display procedure name
  510.     mov    al,SPACE_CHAR
  511. ppn1:    call    putchar
  512.     lodsb
  513.     cmp    al,SPACE_CHAR
  514.     ja    ppn1
  515.     pop    si
  516.  
  517.     lea    ax,resequenced_text    ; * resequenced*
  518.     call    puts_dgroup
  519.     ret
  520. putchar_proc_name endp
  521.  
  522.  
  523. ;;    resequence local label
  524. ;
  525. ;    entry    A    first character of label
  526. ;        DS:SI    points to possible local label
  527. ;        ES:DI    output pointer
  528. ;    exit    DI,SI    updated
  529. ;    uses    AX,BX
  530. ;
  531. resequence_local_label proc
  532.     mov    bx,si
  533.     cmp    al,'9'
  534.     jbe    rll1            ; if possible OPTASM label
  535.  
  536.     cmp    al,proc_initials[bp]    ; check for 3 initial label
  537.     jne    rll2            ;  if not
  538.     mov    al,[si+1]
  539.     cmp    al,proc_initials[bp+1]
  540.     jne    rll2
  541.     mov    al,[si+2]
  542.     cmp    al,proc_initials[bp+2]
  543.     jne    rll2
  544.  
  545.     lea    si,[si+3]        ; try parsing label index
  546.     call    atoi_special
  547.     jc    rll2            ;  if no index, not label
  548.     call    convert_label_index
  549.     jc    rll2            ;  if unknown label index
  550.  
  551.     xchg    bx,si            ; copy procedure initials
  552.     movsw
  553.     movsb
  554.     xchg    bx,si
  555.  
  556.     call    itoa_decimal        ; and write new label index
  557.     ret
  558.  
  559. rll1:    call    atoi_special        ; here for possible OPTASM label
  560.     jc    rll2            ;  if bad index
  561.     cmp    bptr [si],'$'
  562.     jne    rll2            ;  if dollar suffix missing
  563.     call    convert_label_index
  564.     jc    rll2            ;  if unknown index
  565.     call    itoa_decimal
  566.  
  567.     movsb                ; copy dollar suffix
  568.     ret
  569.  
  570. rll2:    mov    si,bx
  571.     ret
  572. resequence_local_label endp
  573.  
  574.  
  575. ;;    resequence proc labels
  576. ;
  577. ;    entry    DS:SI    procedure body
  578. ;        ES:DI    output pointer
  579. ;        CX    line count
  580. ;    exit    DI,SI    updated
  581. ;    uses    AX,BX,CX
  582. ;
  583. resequence_proc_labels proc
  584. rpl1:    mov    al,[si]
  585.     call    isalnum
  586.     jne    rpl3            ; if not label
  587.     call    resequence_local_label    ; else resequence it
  588.     jmp    rpl3
  589.  
  590. rpl2:    movsb                ; skip to next delimiter
  591. rpl3:    mov    al,[si]
  592.     cmp    al,SPACE_CHAR
  593.     je    rpl4
  594.     cmp    al,TAB_CHAR
  595.     je    rpl4
  596.     cmp    al,NL_CHAR
  597.     je    rpl5            ;  if end of line
  598.     cmp    al,';'
  599.     je    rpl5            ;  if comment
  600.     cmp    al,','
  601.     jne    rpl2            ;  if not delimiter
  602.  
  603. rpl4:    movsb                ; delimiter found, skip white space
  604.     mov    al,[si]
  605.     cmp    al,SPACE_CHAR
  606.     je    rpl4            ;  if white space
  607.     cmp    al,TAB_CHAR
  608.     je    rpl4            ;  if white space
  609.     cmp    al,';'
  610.     je    rpl5            ;  if comment
  611.     cmp    al,NL_CHAR
  612.     je    rpl5            ;  if end of line
  613.  
  614.     jmp    rpl1            ; end of white space, check for label
  615.  
  616. rpl5:    lodsb                ; skip to next line
  617.     stosb
  618.     cmp    al,NL_CHAR
  619.     jne    rpl5
  620.  
  621. rpl6:    loop    rpl1            ; loop while more lines left in body
  622.     ret
  623. resequence_proc_labels endp
  624.  
  625.  
  626. ;;    strcpy new ext
  627. ;
  628. ;    entry    DS:SI    asciiz source filename
  629. ;        ES:DI    destination pointer
  630. ;        SS:BX    new extension
  631. ;    exit    DI,SI    updated
  632. ;    uses    AX
  633. ;
  634. strcpy_new_ext proc
  635.     jmp    sne2
  636. sne1:    stosb                ; copy drive, directories, filename
  637. sne2:    lodsb
  638.     cmp    al,NULL_CHAR
  639.     je    sne3            ;  if end of filename
  640.     cmp    al,'.'
  641.     jne    sne1            ;  if not start of extension
  642.  
  643.     mov    al,[si]
  644.     cmp    al,'.'
  645.     je    sne1            ;  if ..
  646.     cmp    al,'\'
  647.     je    sne1            ;  if .\
  648.  
  649. sne3:    mov    al,'.'            ; write new extension
  650.     stosb
  651.     mov    ax,ss:[bx]
  652.     stosw
  653.     mov    al,ss:[bx+2]
  654.     mov    ah,NULL_CHAR
  655.     stosw
  656.     ret
  657. strcpy_new_ext endp
  658.  
  659.  
  660. ;;    update asm source
  661. ;
  662. ;    uses    AX,BX,CX,DX,DI,SI,DS,ES
  663. ;
  664. update_asm_source proc
  665.     test    write_output_flag[bp],-1
  666.     jz    uas2            ;  if nothing to update
  667.  
  668.     lds    si,argv[bp]        ; make .bak filename
  669.     mov    si,[si+2]
  670.     lea    bx,bak_text
  671.     mov    es,dgroup_segment[bp]
  672.     lea    di,bak_filename
  673.     call    strcpy_new_ext
  674.  
  675.     mov    ds,dgroup_segment[bp]    ; delete old .bak file
  676.     lea    si,bak_filename
  677.     call    remove            ;  (ignore errors)
  678.  
  679.     lds    si,argv[bp]        ; rename .asm to .bak
  680.     mov    si,[si+2]
  681.     lea    di,bak_filename
  682.     call    rename
  683.     jc    uas1            ;  if rename failed
  684.  
  685.     call    open_output_file    ; create .asm file
  686.     jc    uas1
  687.  
  688.     mov    cx,output_bc[bp]    ; write .asm file
  689.     les    di,output_bucket[bp]
  690.     call    write_to_file
  691.  
  692.     call    close_file_cf
  693. uas1:    ret
  694.  
  695. uas2:    lea    ax,no_update_text
  696.     call    puts_dgroup
  697.     ret
  698. update_asm_source endp
  699.  
  700.     end
  701.