home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 18 REXX / 18-REXX.zip / rxhll.zip / PREPROC.CMD < prev    next >
OS/2 REXX Batch file  |  1994-02-21  |  12KB  |  409 lines

  1. /**
  2. *** ┌───────────────────────────────────────────────────────────────────────┐
  3. *** │  PreProc.CMD -  Source code preprocessor v2.00                        │
  4. *** │                                                                       │
  5. *** │  This code will parse a source file for '#include' and '#define'      │
  6. *** │  statements and resolve them in a manner similar to the preprocessor  │
  7. *** │  found in many C compilers.  The support for 'define' is simple       │
  8. *** │  string substitution.  This will not handle macro expansion.          │
  9. *** │                                                                       │
  10. *** │  Those included files surrounded by double quotes (") must me in      │
  11. *** │  the current directory.  Those with angle brackets (<>) must be       │
  12. *** │  found in the INCLUDE environment variable.                           │
  13. *** │                                                                       │
  14. *** │  The syntax is:                                                       │
  15. *** │                                                                       │
  16. *** │      PREPROC infile outfile                                           │
  17. *** │                                                                       │
  18. *** │═══════════════════════════════════════════════════════════════════════│
  19. *** │              Copyright (c) 1993, 1994 Hilbert Computing               │
  20. *** │                    Released into the public domain                    │
  21. *** └───────────────────────────────────────────────────────────────────────┘
  22. **/
  23.  
  24. parse arg argstring
  25.  
  26. Opt.  = ''
  27. call ParseOptions argstring
  28. SrcFile = Opt.Parm.1
  29. OutFile = Opt.Parm.2
  30.  
  31. /* Initialize values */
  32.  
  33. Symbol.       = ''
  34.  
  35. Lex.          = ''
  36. Lex.SkipState = 'N'
  37. Lex.SkipNest  = 0
  38. Lex.Nest      = 0
  39. Lex.LineCount = 0
  40.  
  41. if Opt.Flag.SYNTAX = '+' then
  42.    call Syntax
  43.  
  44. if SrcFile = '' then
  45.    do
  46.    say 'Error: You must specify an input file.'
  47.    call Syntax
  48.    end
  49.  
  50. if OutFile = '' then
  51.    do
  52.    say 'Error: You must specify an output file.'
  53.    call Syntax
  54.    end
  55.  
  56. call LoadFunctions
  57.  
  58. /* Emit the header information */
  59.  
  60. say "Source file preprocessor.  Version 2.00"
  61. say "Copyright (c) 1994, Hilbert Computing"
  62. say
  63.  
  64. OutFile = open(OutFile, 'WRITE')
  65. call time('Reset')
  66. Lex.Indent = 1
  67. call ProcessFile SrcFile
  68. say
  69. say  Lex.LineCount "lines processed in" format(time('Elapsed'),,2) "seconds."
  70. exit
  71.  
  72.  
  73. ProcessFile: procedure expose Symbol. Lex. OutFile
  74.    /**
  75.    *** This will handle the symbol resolution for a single file
  76.    **/
  77.  
  78.    parse arg SrcFile
  79.  
  80.    say  "Processing file:"copies(" ", Lex.Indent) SrcFile
  81.  
  82.    if (\exists(SrcFile)) then
  83.       do
  84.       say
  85.       say 'Error: Input file "'SrcFile'" doesn''t exist.'
  86.       return
  87.       end
  88.  
  89.    LineNo = 0
  90.    Src = open(SrcFile, 'READ')
  91.    do while(lines(Src) > 0)
  92.       line = linein(Src)
  93.       Lex.LineCount = Lex.LineCount + 1
  94.       LineNo = LineNo + 1
  95.       FirstWord = translate(word(line, 1))
  96.  
  97.       select
  98.          when FirstWord = "#INCLUDE" then
  99.             do
  100.  
  101.             if Lex.SkipState = 'N' then
  102.                do
  103.                Lex.Indent = Lex.Indent + 3
  104.                call ProcessInclude line
  105.                Lex.Indent = Lex.Indent - 3
  106.                say "Processing file:"copies(" ", Lex.Indent) SrcFile
  107.                end
  108.             end
  109.          when FirstWord = "#DEFINE" then
  110.             do
  111.             if Lex.SkipState = 'N' then
  112.                do
  113.                parse var line . SymName SymValue
  114.                SymValue = strip(SymValue)
  115.  
  116.                /* Add this to the symbol table */
  117.  
  118.                Symbol.SymName = SymValue
  119.                Lex.Tails = Lex.Tails SymName
  120.                end
  121.             end
  122.          when FirstWord = "#IFDEF" then
  123.             do
  124.             parse var line . SymName
  125.             if wordpos(SymName, Lex.Tails) = 0 then
  126.                Lex.SkipState = 'Y'
  127.  
  128.             Lex.Nest = Lex.Nest + 1
  129.             if Lex.SkipState = 'Y' then
  130.                Lex.SkipNest = Lex.SkipNest + 1
  131.             end
  132.          when FirstWord = "#IFNDEF" then
  133.             do
  134.             parse var line . SymName
  135.             if wordpos(SymName, Lex.Tails) <> 0 then
  136.                Lex.SkipState = 'Y'
  137.  
  138.             Lex.Nest = Lex.Nest + 1
  139.             if Lex.SkipState = 'Y' then
  140.                Lex.SkipNest = Lex.SkipNest + 1
  141.             end
  142.          when FirstWord = "#ENDIF" then
  143.             do
  144.             if Lex.Nest = 0 then
  145.                do
  146.                say 'Error('SrcFile':'LineNo'): Too many #ENDIF statements'
  147.                exit
  148.                end
  149.             else
  150.                Lex.Nest = Lex.Nest - 1
  151.  
  152.             if Lex.SkipState = 'Y' then
  153.                Lex.SkipNest = Lex.SkipNest - 1
  154.  
  155.             if Lex.SkipNest = 0 then
  156.                Lex.SkipState = 'N'
  157.             end
  158.          otherwise
  159.             do
  160.             if Lex.SkipState = 'N' then
  161.                do
  162.                line = Resolve(line)
  163.                call lineout OutFile,line
  164.                end
  165.             end
  166.       end /* select */
  167.    end /* while */
  168.    call Close(SrcFile)
  169.    return
  170.  
  171.  
  172. ProcessInclude: procedure expose Symbol. Lex. OutFile
  173.    /**
  174.    ***  This will handle the processing for the '#include' keyword
  175.    **/
  176.  
  177.    parse arg line
  178.  
  179.  
  180.    if pos('"', line) > 0 then
  181.       parse var line '"' IncludeFile '"'
  182.    else
  183.       do
  184.       parse var line '<' SearchFile '>'
  185.       IncludeFile = SysSearchPath('INCLUDE', SearchFile)
  186.       if IncludeFile = "" then
  187.          do
  188.          say
  189.          say 'Error: Include file "'SearchFile'" doesn''t exist.'
  190.          return
  191.          end
  192.       end
  193.    call ProcessFile IncludeFile
  194.    return
  195.  
  196.  
  197. Resolve: procedure expose Symbol.
  198.  
  199.    parse arg line
  200.  
  201.    do i = 1 to words(Lex.Tails)
  202.       Sym = word(Lex.Tails, i)
  203.       if pos(Sym, line) > 0 then
  204.          do
  205.          parse var line prefix (Sym) suffix
  206.          line = prefix || Symbol.Sym || suffix
  207.          end
  208.    end
  209.    return line
  210.  
  211. Syntax: procedure
  212.    /**
  213.    ***  Display syntax information and exit
  214.    **/
  215.  
  216.    say
  217.    say "Syntax:  PREPROC in out"
  218.    say
  219.    say "where 'in' is the input file and 'out' is the output file."
  220.    exit
  221.  
  222.  
  223. /* #include <io.rex> */
  224.  
  225. Close: procedure
  226.    /**
  227.    ***  Close a file I/O stream
  228.    **/
  229.    parse arg file
  230.    message = stream(file,c,'CLOSE')
  231.    if (message <> 'READY:') & (message <> '') then
  232.       do
  233.       say 'Error: Close failure on' file'.' message
  234.       exit
  235.       end
  236.    return file
  237.  
  238.  
  239. Exists: procedure
  240.    /**
  241.    *** Return a Boolean indicating whether the file exists or not
  242.    **/
  243.    arg file
  244.  
  245.    file = stream(file,c,'QUERY EXIST')
  246.    if (file = '') then
  247.       return 0
  248.    else
  249.       return 1
  250.  
  251.  
  252. Open: procedure
  253.    /**
  254.    *** Open a file for READ, WRITE, APPEND or RANDOM (read/write)
  255.    **/
  256.    parse arg file, rw
  257.    rw = translate(rw)
  258.  
  259.    select
  260.       when rw = 'WRITE' then
  261.          do
  262.          file_ = stream(file,c,'QUERY EXIST')
  263.          if file_ <> '' then
  264.             '@erase "'file'" 2> NUL'
  265.          end
  266.       when rw = 'APPEND' then
  267.          rw = 'WRITE'
  268.       when rw = 'READ' then
  269.          rw = 'READ'
  270.       when rw = 'RANDOM' then
  271.          rw = ''
  272.       otherwise
  273.          rw = 'READ'
  274.    end /* select */
  275.  
  276.    message = stream(file,c,'OPEN' rw)
  277.    if (message \= 'READY:') then
  278.       do
  279.       say 'Error: Open failure on' file'.' message
  280.       return message
  281.       end
  282.    return file
  283.  
  284. /* #include LoadFunctions.rex */
  285.  
  286. LoadFunctions: procedure
  287.    /**
  288.    ***   This will load the DLL for the Rexx system functions supplied
  289.    ***   with OS/2 v2.0
  290.    **/
  291.    call RxFuncAdd 'SysLoadFuncs', 'RexxUtil', 'SysLoadFuncs'
  292.    call SysLoadFuncs
  293.    return
  294.  
  295. /* #include <parseopt.rex> */
  296.  
  297. ParseOptions: procedure expose Opt.
  298.    /**
  299.    ***  This will parse the command line options.  Those parameters that
  300.    ***  begin with a minus (-) or forward slash (/) are considered flags
  301.    ***  and are placed in Opt.Flag.   The remaining options are placed
  302.    ***  into Opt.parm.<x>.
  303.    ***
  304.    ***  NOTE:  This code does not clear out the 'Opt.' stem variable since
  305.    ***         the caller may want to establish defaults prior to calling
  306.    ***         this code.
  307.    ***
  308.    ***  LIMITATIONS:  The code currently only looks for the double quote
  309.    ***         character (").  The apostrophe is treated like any other
  310.    ***         character.  The way this is currently coded, multiple blanks
  311.    ***         in a quoted string are compressed to a single blanks and
  312.    ***         probably should not be.
  313.    ***
  314.    **/
  315.  
  316.    parse arg arguments
  317.  
  318.    Opt.Flag.List = ''
  319.    Opt.State = 'Normal'
  320.    j = 0
  321.    do i = 1 to words(arguments)
  322.       argument = word(arguments, i)
  323.  
  324.       select
  325.          when Opt.State = 'Quoted Positional' then
  326.             do
  327.             /* Keep appending the words to this parm until an ending quote */
  328.             /* is found.                                                   */
  329.  
  330.             Opt.Parm.j = Opt.Parm.j argument
  331.             if right(argument,1) = '"' then
  332.                do
  333.                Opt.Parm.j = strip(Opt.Parm.j, 'Both', '"')
  334.                Opt.State = 'Normal'
  335.                end
  336.             end
  337.          when Opt.State = 'Quoted Flag' then
  338.             do
  339.             /* Keep appending until the terminating quote is found */
  340.  
  341.             Opt.Flag.Flagname = Opt.Flag.FlagName argument
  342.             if right(argument,1) = '"' then
  343.                do
  344.                Opt.Flag.Flagname = strip(Opt.Flag.Flagname, 'Both', '"')
  345.                Opt.State = 'Normal'
  346.                end
  347.             end
  348.          when Opt.State = 'Normal' then
  349.             do
  350.             FirstChar = left(argument, 1)
  351.             if ((FirstChar = '-') | (FirstChar = '/')) then
  352.                do
  353.                /*  This is a flag.  The value of the flag is the remainder of  */
  354.                /*  the string.  If the remainder is the null string, then it   */
  355.                /*  has an implicit value of '+' implying "on" or "true"        */
  356.  
  357.                FlagName = substr(argument, 2, 1)   /* Second character     */
  358.                FlagName = translate(FlagName)      /* Convert to uppercase */
  359.  
  360.                /* See if this flag parm is quoted */
  361.  
  362.                if substr(argument, 3, 1) = '"' then
  363.                   Opt.State = 'Quoted Flag'
  364.  
  365.                /* If any of the flag names are not a valid character for a REXX */
  366.                /* variable, we have to translate into a mnemonic.               */
  367.  
  368.                if ((FlagName < 'A') | (FlagName > 'Z')) then
  369.                   do
  370.                   select
  371.                      when FlagName = '?' then FlagName = 'SYNTAX'
  372.                      when FlagName = '!' then FlagName = 'BANG'
  373.                      when FlagName = '*' then FlagName = 'STAR'
  374.                      when FlagName = '#' then FlagName = 'POUND'
  375.                      when FlagName = '$' then FlagName = 'DOLLAR'
  376.                      when FlagName = '%' then FlagName = 'PERCENT'
  377.                      when FlagName = '^' then FlagName = 'HAT'
  378.                      when FlagName = '&' then FlagName = 'AMP'
  379.                      when FlagName = '(' then FlagName = 'LPAR'
  380.                      when FlagName = ')' then FlagName = 'RPAR'
  381.                      when FlagName = '-' then FlagName = 'DASH'
  382.                      when FlagName = '=' then FlagName = 'EQUAL'
  383.                      otherwise /* Force a syntax message */
  384.                         FlagName = 'SYNTAX'
  385.                   end /* select */
  386.                   end /* if */
  387.  
  388.                FlagValue = substr(argument, 3)     /* Remainder of string */
  389.                if FlagValue = '' then
  390.                   FlagValue = '+'
  391.  
  392.                Opt.Flag.FlagName = FlagValue
  393.                Opt.Flag.List = FlagName Opt.Flag.List
  394.                end
  395.             else /* it is a positional parameter */
  396.                do
  397.                j = j + 1
  398.                Opt.Parm.j = argument
  399.                if left(argument,1) = '"' then
  400.                   Opt.State = 'Quoted Positional'
  401.                end
  402.          end /* 'Normal' */
  403.       otherwise
  404.          nop
  405.       end /* select */
  406.    end /* do i... */
  407.    Opt.Parm.0 = j
  408.    return
  409.