PASCAL MACRO COMPILER
Keyword String Macros



       The Keyword String macros are useful in two situations that are often encountered in software projects.

       The first situation is when a program receives input in the form of words or commands. These may be interactive, like a person entering commands or queries to the program through a keyboard, or they may be words that occur in data files, transaction records or archives. In this case, the program may have internal constants or codes that represent the possible values of the user keywords.

       The second situation is the reverse. The program may have a set of internal constants that represent the possible values of some variable. The program may need to have words or phrases to communicate these values to the user in report headings, error messages or output files.

       If the set of values is fairly static, then there may be no problem. But if the values change frequently, say the user adds new products, colors, models, departments, materials or pricing categories often, then there can be a problem keeping the internal and external codes in sync. The Keyword String macros are designed to make this process automatic.

       This version is intended mainly as a demonstration. The user should adjust the table sizes and keyword sizes appropriately for the application. The DefKCodes and DefKWords tables should be set large enough to allow adding new keywords without having to make repeated adjustments. Appropriate code should be inserted in DefKeyword to handle any table overflows.

       There are few comments inside the macro procedures. This has been done to prevent the comments from appearing in the generated code. The user may wish to add comments appropriate to the application, such as naming the tables. If there are multiple sets of keywords, each set could get a suitable title in the generated code by adding a parameter to DefKEnd or DefKPack.

  {Keyword String Macros				      }
  {					   Frank Rubin 2/8/05 }
  {							      }
  {   These macros define a set of keywords for the Pascal    }
  {program.  These keywords are words or names specific to the}
  {Pascal program that have been used to identify actions or  }
  {objects.   For example, a graphics application might use   }
  {keywords such as DRAW, SHAPE, CIRCLE, etc., while a drink  }
  {application might use keywords COFFEE, TEA, SODA, etc.     }
  {							      }
  {   The macros produce arrays of declarations which may be  }
  {in either packed or aligned format.	In packed format the  }
  {keywords are inserted into the table with no space between }
  {entries.  In aligned format each keyword occupies the same }
  {amount of space, with gaps between entries.		      }
  {							      }
  {The packed format produces:				      }
  {1. A packed table of strings containing the names of the   }
  {   keywords (commands, product names, departments, etc).   }
  {2. A table of offsets into the packed table of keywords.   }
  {   These point to the start of each keyword. 	      }
  {3. A table of indices into the table of offsets.  These    }
  {   define the constants corresponding to the keywords.     }
  {							      }
  {The aligned format produces: 			      }
  {1. An array of strings containing the names of the keywords}
  {   (commands, product names, departments, etc).	      }
  {2. A table of indices into the array of keywords.  These   }
  {   define the constants corresponding to the keywords.     }
  {							      }
  {   Using these macros lets the Pascal programmer define a  }
  {set of Pascal constants that represent the keywords.  Using}
  {the macros instead of simply writing a set of declarations }
  {keeps the keywords and constants in step.  That is, the two}
  {mappings  keyword --> constant  and	constant --> keyword  }
  {are always in sync.	This can be valuable for applications }
  {where keywords are added, deleted and changed frequently.  }
  {							      }
  {   An application might have several different sets of     }
  {keywords, for example product categories, warehouse names, }
  {shipper names, pricing codes, etc.			      }

  {There are 4 macro procedures in the set:		      }
  {							      }
  {DefKTable   Starts a set of keyword definitions.	      }
  {DefKeyword  Defines one keyword, command, name, etc.       }
  {DefKEnd     Indicates the end of the definitions and       }
  {	       generates aligned tables.		      }
  {DefKPack    Indicates the end of the definitions and       }
  {	       generates packed tables. 		      }
  {							      }
  {Note that the %Include for these macro procedures must be  }
  {placed in the declaration portion of the macro program, and}
  {the calls to these procedures must be placed in the body of}
  {the macro program.					      }

  {EXAMPLE #1 (aligned format): 			      }
  {							      }
  {  %DefKTable;					      }
  {  %DefKeyword ('rd', 'RED');                               }
  {  %DefKeyword ('ye', 'YELLOW');                            }
  {  %DefKeyword ('gr', 'GREEN');                             }
  {  %DefKEnd (traffic);				      }
  {							      }
  {produces						      }
  {							      }
  {  Const						      }
  {    rd = 1;						      }
  {    ye = 2;						      }
  {    gr = 3;						      }
  {  Const						      }
  {    traffic: array[1..4] of string[20] = (		      }
  {    'RED',                                                 }
  {    'YELLOW',                                              }
  {    'GREEN');                                              }
  {							      }
  {EXAMPLE #2 (packed format):				      }
  {							      }
  {  %DefKTable;					      }
  {  %DefKeyword ('rd', 'RED');                               }
  {  %DefKeyword ('ye', 'YELLOW');                            }
  {  %DefKeyword ('gr', 'GREEN');                             }
  {  %DefKPack (traffic,toffset);			      }
  {							      }
  {produces						      }
  {							      }
  {  Const						      }
  {    rd = 1;						      }
  {    ye = 2;						      }
  {    gr = 3;						      }
  {  Const						      }
  {    toffset: array[1..3] of integer = (		      }
  {    1, 5, 12);					      }
  {  Const						      }
  {    traffic: array[1..17] of char = (		      }
  {    #3, 'R', 'E', 'D',                                     }
  {    #6, 'Y', 'E', 'L', 'L', 'O', 'W',                      }
  {    #5, 'G', 'R', 'E', 'E', 'N');                          }
  {							      }
  {In both of these examples, the constants rd, ye and gr will}
  {always correspond to the keywords RED, YELLOW and GREEN    }
  {even if the order changes or other keywords are added in   }
  {between.						      }



  {DefKTable						      }
  {   DefKTable starts a set of keyword definitions. DefKTable}
  {should be called before any keywords are defined using     }
  {DefKeyword.						      }
  {   Each set of keywords is independent of the others.  For }
  {example, an application could have department names aligned}
  {but product names packed.  Each set of keywords must begin }
  {with DefKTable and end with either DefKEnd or DefKPack.    }

  {--These tables should be adjusted to suit the application--}
%Var
  DefKCount: integer;			    {The number of keywords}
  DefKCodes: array[1..100] of string[20];   {Internal codes for the keywords}
  DefKWords: array[1..100] of string[20];   {The keywords}

%Procedure  DefKTable;	 {Start a set of keywords}
%Begin	{DefKTable}
  %DefKCount := 0;	 {Empty the keyword table}
%End;  {DefKTable}


  {DefKeyword							 }
  {   DefKeyword defines one keyword.  It establishes the mapping}
  {between the Pascal variable and the keyword.  DefKeyword is	 }
  {called once for each keyword.				 }
  {								 }
  {PasVar   The Pascal variable representing the keyword.	 }
  {Keyword  The keyword being defined.				 }
%Procedure  DefKeyword (PasVar, Keyword: string);
%Begin	{DefKeyword}
  %if  DefKCount < 100
       then  %begin
	       %DefKCount := DefKCount + 1;
	       %DefKCodes[DefKCount] := PasVar;
	       %DefKWords[DefKCount] := Keyword;
	     %end;
  {The user can add code here to handle any table overflow}
%End;  {DefKeyword}


   {DefKEnd						    }
   {   DefKEnd is called after all of the keywords have been}
   {defined to generate Pascal declarations for the aligned }
   {array of keywords.	DefKEnd is used in the body of the  }
   {macro program, but the declarations should be placed in }
   {the declaration section of the generated Pascal program.}
   {							    }
   {name  The name of the keyword array.		    }
%Procedure  DefKEnd (name: code);
%Var
  n: integer;
%Begin	{DefKEnd}
%if  DefKCount = 0
     then  %exit;
Const
%;
%for  n := 1 to DefKCount  do
  DefKCodes[n] = n;
Const
  name: array[1..DefKCount] of string[20] = (
%;
%for  n := 1 to DefKCount-1  do
  _quote%DefKWords[n]%_quote,
%;
  _quote%DefKWords[DefKCount]%_quote);
%End;  {DefKEnd}


   {DefKPack						     }
   {   DefKPack is called after all of the keywords have been}
   {defined to generate Pascal declarations for the packed   }
   {table of keywords.	DefKPack is used in the body of the  }
   {macro program, but the declarations should be placed in  }
   {the declaration section of the generated Pascal program. }
   {   The offset array points to the first character of each}
   {keyword, making it possible to search the keyword array  }
   {with a simple loop. 				     }
   {							     }
   {kname  The name of the packed keyword array.	     }
   {oname  The name of the offset array.		     }
%Procedure  DefKPack (kname, oname: code);
%Var
  n,len,i: integer;
%Begin	{DefKPack}
%if  DefKCount = 0
     then  %exit;
Const
%;
%for  n := 1 to DefKCount  do
  DefKCodes[n] = n;
Const
%;
  oname: array[1..DefKCount] of integer = (
  %;
%len := 1;
%for  n := 1 to DefKCount-1  do %begin
len, %;
%if  (n mod 10) = 0
     then  _col(3)%;
%len := len + _length(DefKWords[n]) + 1;
%end;
len);

%len := len + _length(DefKWords[DefKCount]);
Const
  kname: array[1..len] of char = (
%;
%for  n := 1 to DefKCount-1  do %begin
  %len := _length(DefKWords[n]);
  #%len, %;
%for  i := 1 to len  do
_quote%DefKWords[n,i]%_quote, %;
_line%;
%end;
  %len := _length(DefKWords[DefKCount]);
  #%len, %;
%for  i := 1 to len-1  do
_quote%DefKWords[DefKCount,i]%_quote, %;
%;
_quote%DefKWords[DefKCount,len]%_quote);
%End;  {DefKPack}


© Copyright 2005 Frank Rubin