home *** CD-ROM | disk | FTP | other *** search
/ Programmer 7500 / MAX_PROGRAMMERS.iso / PASCAL / MPREP.ZIP / MPREP.PAS < prev   
Encoding:
Pascal/Delphi Source File  |  1987-01-12  |  13.6 KB  |  347 lines

  1. program MPREP;
  2. { Macro Preprocessor and version control program to give C-like preprocessing
  3.   to programs written in any language (or general text).
  4.   The following commands can be embedded in any ASCII file
  5.   (They must start with a '#' as the first character of a new line):
  6.      #define identifier [string]
  7.      #ifdef identifier
  8.      #ifndef identifier
  9.      #endif
  10.   In addition, using the identifier in any text following its definition
  11.   results in replacement of the identifier by the string that followed
  12.   it in the #define statement. (Macros can contain references to previously-
  13.   defined macros.) MPREP is invoked as:
  14.      MPREP [-E ext] [-D identifier] filename [filename2] [filename3] ...
  15.   where ext is an optional filename extension, which is used to name the
  16.   output file (the default is PAS). For example, the command:
  17.      MPREP MAIN.PRE
  18.   would result in the creation of an output file named MAIN.PAS.
  19.   Identifiers specified with the -D flag will define the identifier.
  20.   Note that all identifiers that are defined on the command line and
  21.   in the files are defined for all files listed. Also, it should be noted
  22.   that all commands in MPREP are case-sensitive. Thus, an identifier specified
  23.   in capital letters will not be confused with the same identifier in lower
  24.   case. The only exception is the letters '-D' and '-E' on the command line,
  25.   which may be specified in either upper or lower case.
  26.      I won't bother going into specifics on how to use the #define, #ifdef,
  27.   #ifndef, and #endif commands. Any book on the C language can tell you how
  28.   they work. (The only differences between my version and standard C are
  29.   (1) In mine, macro definitions that contain previously-defined macros are
  30.   expanded; and (2) I have not bothered to implement the optional designation
  31.   of an identifier after #endif. It always goes with the last open #ifdef or
  32.   #ifndef.)
  33.                         Ken Van Camp
  34.                         P.O. Box 784
  35.                         Stroudsburg, PA 18360
  36.   MPREP may be freely distributed, or distributed at nominal copying/mailing
  37.   fee, but may not be otherwise charged for. It may not be incorporated into
  38.   commercial software without express written permission of the author.
  39. }
  40.  
  41. const MAXDEF = 200;         { max # defines }
  42.  
  43. type nametype   = string[40];
  44.      stringtype = string[70];
  45.      filetype   = string[40];
  46.  
  47. var Defname:      array[1..MAXDEF] of nametype;   { defined names }
  48.     Defstring:    array[1..MAXDEF] of stringtype; { strings defined by Defname}
  49.     Extension:    string[4];    { filename extension for output files }
  50.     Param:        integer;      { cmmd-line parameter # }
  51.     Filin:        text;         { input files }
  52.     Filout:       text;         { output files }
  53.     Numdef:       integer;      { # defined names }
  54.     Nextext:      boolean;      { flag that next param is an extension }
  55.     Nextdef:      boolean;      { flag that next param is a definition }
  56.     Line:         string[255];  { line inputted from file }
  57.     Lenline:      integer;      { length of line }
  58.     Startstr:     integer;      { start pos of define string }
  59.     Endstr:       integer;      { end pos of define string }
  60.     Defined:      boolean;      { flag OK to echo lines to file }
  61.     Name:         nametype;     { name of define macro }
  62.     Def:          integer;      { define # }
  63.     Found:        boolean;      { flag found define name }
  64.     Nif:          integer;      { # open ifdef's or ifndef's }
  65.     Ifdef:        integer;      { flag the ifdef that stopped echoing }
  66.     Fdpos:        integer;      { position where macro name was found }
  67.     Fileread:     boolean;      { flag that a file was read }
  68.     Nextc:        integer;      { next character after macro names }
  69.  
  70. procedure USAGE;
  71. begin
  72.   writeln ('usage: PREP [-E ext] [-D defname] flnm [flnm2] [flnm3] ...');
  73.   halt;
  74. end; { procedure USAGE }
  75.  
  76. procedure MAXEXCEED;
  77. begin
  78.   writeln ('PREP: Maximum # of defines (',MAXDEF,') exceeded.');
  79.   halt;
  80. end; { procedure MAXEXCEED }
  81.  
  82. function ISALPHANUM (c: char): boolean;
  83. { Returns TRUE if c is alphanumeric }
  84. begin
  85.   if ((c>='0') and (c<='9')) or ((c>='A') and (c<='Z')) or
  86.      ((c>='a') and (c<='z')) then
  87.     ISALPHANUM := TRUE
  88.   else
  89.     ISALPHANUM := FALSE;
  90. end; { function ISALPHANUM }
  91.  
  92. procedure OPENFILIN (Filename: filetype; var Filin: text);
  93. { Open the input file, with error checking }
  94.  
  95. var Flnm: filetype;
  96.     Fileopen: boolean;
  97.  
  98. begin
  99.   Fileopen := FALSE;
  100.   Flnm := Filename;
  101.   while (NOT Fileopen) do begin
  102.     assign (Filin, Flnm);
  103.     {$I-}
  104.     reset (Filin);
  105.     {$I+}
  106.     if (ioresult <> 0) then begin
  107.       write ('Input file ',Flnm,' cannot be opened. Enter new filename: ');
  108.       readln (Flnm);
  109.       if (Flnm = '') then
  110.         halt;
  111.     end else
  112.       Fileopen := TRUE;
  113.   end; { while }
  114. end; { procedure OPENFILIN }
  115.  
  116. procedure OPENFILOUT (Filename: filetype; var Filout: text);
  117. { Open the output file, with error checking}
  118.  
  119. var Flnm:     filetype;
  120.     Fileopen: boolean;
  121.     Period:   integer;   { location of period in file name }
  122.  
  123. begin
  124.   Fileopen := FALSE;
  125.   Flnm := Filename;
  126.   while (NOT Fileopen) do begin
  127.     Period := pos ('.', Flnm);
  128.     if (Period > 0) then
  129.       Flnm := copy (Flnm, 1, Period-1);
  130.     { Check to see if the user put a period in the filename extension }
  131.     if (Extension[1] = '.') then
  132.       Flnm := Flnm + Extension
  133.     else
  134.       Flnm := Flnm + '.' + Extension;
  135.     if (Flnm = Filename) then begin
  136.       writeln ('MPREP: Input and output filenames (',Flnm,') are same.');
  137.       halt;
  138.     end;
  139.     assign (Filout, Flnm);
  140.     {$I-}
  141.     rewrite (Filout);
  142.     {$I+}
  143.     if (ioresult <> 0) then begin
  144.       write ('Output file ',Flnm,' cannot be opened. Enter new file name: ');
  145.       readln (Flnm);
  146.       if (Flnm = '') then
  147.         halt;
  148.     end else
  149.       Fileopen := TRUE;
  150.   end; { while }
  151. end; { procedure OPENFILOUT }
  152.  
  153. begin { program PREP }
  154.   { Initializations }
  155.   Fileread := FALSE;
  156.   Extension := 'PAS';          { default is for Pascal file extension }
  157.   Nextext := FALSE;
  158.   Nextdef := FALSE;
  159.   Numdef := 0;
  160.   Defined := TRUE;
  161.   Nif := 0;
  162.   Ifdef := 0;
  163.  
  164.   for Param := 1 to paramcount do begin
  165.     if (Nextext) then begin
  166.       { Last parameter was -E, so this parameter is the filename extension. }
  167.       if (length (paramstr (Param)) > 3) then
  168.         usage;
  169.       Extension := paramstr (Param);
  170.       Nextext := FALSE;
  171.     end else if (Nextdef) then begin
  172.       { Last parameter was -D, so this parameter is a definition. }
  173.       Numdef := Numdef + 1;
  174.       if (Numdef > MAXDEF) then
  175.         maxexceed;
  176.       Defname[Numdef] := paramstr (Param);
  177.       Defstring[Numdef] := '';
  178.       Nextdef := FALSE;
  179.     end else if (copy (paramstr(Param),1,2) = '-e') or
  180.                 (copy (paramstr(Param),1,2) = '-E') then begin
  181.       { -E flag found; next parameter should contain filename extension }
  182.       Nextext := TRUE;
  183.     end else if (copy (paramstr(Param),1,2) = '-d') or
  184.                 (copy (paramstr(Param),1,2) = '-D') then begin
  185.       { -D flag found; next parameter should contain definition }
  186.       Nextdef := TRUE;
  187.     end else begin
  188.       { Just a normal file name }
  189.       openfilin (paramstr (Param), Filin);
  190.       openfilout(paramstr (Param), Filout);
  191.       Fileread := TRUE;
  192.  
  193.       { Now read the file & process the define's }
  194.       repeat
  195.         readln (Filin, Line);
  196.         Lenline := length (Line);
  197.         if (copy (Line,1,8) = '#define ') then begin
  198.           { Find the #define name }
  199.           { (Starts at first non-blank & non-tab.) }
  200.           Startstr := 9;
  201.           while (Startstr <= Lenline) and ((Line[Startstr] = ' ') or
  202.                 (Line[Startstr] = ^I)) do
  203.             Startstr := Startstr + 1;
  204.           if (Startstr <= Lenline) then begin
  205.             { Name was found; define it }
  206.             Numdef := Numdef + 1;
  207.             if (Numdef > MAXDEF) then
  208.               maxexceed;
  209.             Endstr := Startstr + 1;
  210.             while (Endstr <= Lenline) and (Line[Endstr] <> ' ') and
  211.                   (Line[Endstr] <> ^I) do
  212.               Endstr := Endstr + 1;
  213.             if (Endstr > Lenline) then
  214.               Endstr := Lenline;
  215.             Defname[Numdef] := copy (Line, Startstr, Endstr-Startstr);
  216.  
  217.             { Now find the string defined, if it exists }
  218.             Startstr := Endstr + 1;
  219.             while (Startstr <= Lenline) and ((Line[Startstr] = ' ') or
  220.                   (Line[Startstr] = ^I)) do
  221.               Startstr := Startstr + 1;
  222.             if (Startstr <= Lenline) then begin
  223.               { Definition was found }
  224.               Defstring[Numdef] := copy (Line, Startstr, Lenline);
  225.               { Check for any other macros within the definition }
  226.               for Def := 1 to Numdef-1 do
  227.                 if (Defstring[Def] <> '') then begin
  228.                   Fdpos := pos (Defname[Def], Defstring[Numdef]);
  229.                   if (Fdpos > 0) then begin
  230.                     Found := TRUE;
  231.                     if (Fdpos > 1) then
  232.                       if isalphanum (Defstring[Numdef][Fdpos-1]) then
  233.                         Found := FALSE;
  234.                     Nextc := Fdpos + length (Defname[Def]);
  235.                     if (Found) and (Nextc <= length(Defstring[Numdef])) then
  236.                       if isalphanum (Defstring[Numdef][Nextc]) then
  237.                         Found := FALSE;
  238.                     if (Found) then
  239.                       Defstring[Numdef] := copy (Defstring[Numdef],1,Fdpos-1)
  240.                         + Defstring[Def] +
  241.                         copy (Defstring[Numdef],Fdpos+length(Defname[Def]),
  242.                         length(Defstring[Numdef]));
  243.                   end; { if Fdpos }
  244.                 end; { if Defstring[Def] }
  245.               { for Def }
  246.             end else
  247.               { No definition }
  248.               Defstring[Numdef] := '';
  249.           end; { if Startstr }
  250.         end else if (copy (Line,1,7) = '#ifdef ') then begin
  251.           Nif := Nif + 1;
  252.           if (Defined) then begin
  253.             Startstr := 8;
  254.             while (Startstr <= Lenline) and ((Line[Startstr] = ' ') or
  255.                   (Line[Startstr] = ^I)) do
  256.               Startstr := Startstr + 1;
  257.             if (Startstr <= Lenline) then begin
  258.               { Name was found; find the end of it }
  259.               Endstr := Startstr + 1;
  260.               while (Endstr <= Lenline) and (Line[Endstr] <> ' ') and
  261.                     (Line[Endstr] <> ^I) do
  262.                 Endstr := Endstr + 1;
  263.               if (Endstr > Lenline) then
  264.                 Endstr := Lenline;
  265.               Name := copy (Line, Startstr, Endstr-Startstr+1);
  266.               { Now see if the name was defined }
  267.               Found := FALSE;
  268.               for Def := 1 to Numdef do
  269.                 if (Defname[Def] = Name) then
  270.                   Found := TRUE;
  271.               if (Found) then
  272.                 Defined := TRUE
  273.               else begin
  274.                 Defined := FALSE;
  275.                 Ifdef := Nif;
  276.               end; { if Found }
  277.             end; { if Startstr }
  278.           end; { if Defined }
  279.         end else if (copy (Line,1,8) = '#ifndef ') then begin
  280.           Nif := Nif + 1;
  281.           if (Defined) then begin
  282.             Startstr := 9;
  283.             while (Startstr <= Lenline) and ((Line[Startstr] = ' ') or
  284.                   (Line[Startstr] = ^I)) do
  285.               Startstr := Startstr + 1;
  286.             if (Startstr <= Lenline) then begin
  287.               { Name was found; find the end of it }
  288.               Endstr := Startstr + 1;
  289.               while (Endstr <= Lenline) and (Line[Endstr] <> ' ') and
  290.                     (Line[Endstr] <> ^I) do
  291.                 Endstr := Endstr + 1;
  292.               if (Endstr > Lenline) then
  293.                 Endstr := Lenline;
  294.               Name := copy (Line, Startstr, Endstr-Startstr+1);
  295.               { Now see if the name was defined }
  296.               Found := FALSE;
  297.               for Def := 1 to Numdef do
  298.                 if (Defname[Def] = Name) then
  299.                   Found := TRUE;
  300.               if (Found) then begin
  301.                 Defined := FALSE;
  302.                 Ifdef := Nif;
  303.               end else
  304.                 Defined := TRUE;
  305.             end; { if Startstr }
  306.           end; { if Defined }
  307.         end else if (copy (Line,1,6) = '#endif') then begin
  308.           if (Ifdef = Nif) then begin
  309.             Defined := TRUE;
  310.             Ifdef := 0;
  311.           end;
  312.           Nif := Nif - 1;
  313.         end else if (Defined) then begin
  314.           { No preprocessor directives; just a normal line }
  315.           { Check for any defined macros }
  316.           Def := 1;
  317.           Found := FALSE;
  318.           while (Def <= Numdef) and (NOT Found) do begin
  319.             if (Defstring[Def] <> '') then begin
  320.               Fdpos := pos (Defname[Def], Line);
  321.               if (Fdpos > 0) then begin
  322.                 Found := TRUE;
  323.                 if (Fdpos > 1) then
  324.                   if (isalphanum (Line[Fdpos-1])) then
  325.                     Found := FALSE;
  326.                 Nextc := Fdpos + length(Defname[Def]);
  327.                 if (Found) and (Nextc <= Lenline) then
  328.                   if (isalphanum (Line[Nextc])) then
  329.                     Found := FALSE;
  330.                 Line := copy (Line,1,Fdpos-1) + Defstring[Def] +
  331.                         copy (Line,Fdpos+length(Defname[Def]),Lenline);
  332.               end; { if Fdpos > 0 }
  333.             end; { if Defstring[Def] }
  334.             Def := Def + 1;
  335.           end; { while Def... }
  336.           writeln (Filout, Line);
  337.         end; { if copy(Line,1,8)... }
  338.  
  339.       until eof (Filin);
  340.       close (Filin);
  341.       close (Filout);
  342.     end; { if Nextext... }
  343.   end; { for Param }
  344.   if (NOT Fileread) then
  345.     usage;
  346. end. { program PREP }
  347.