home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / pmos2002.zip / UTIL / SRC / PPEXPR.MOD < prev    next >
Text File  |  1996-07-25  |  13KB  |  364 lines

  1. IMPLEMENTATION MODULE PPExpr;
  2.  
  3.         (********************************************************)
  4.         (*                                                      *)
  5.         (*         Expression handler for preprocessor          *)
  6.         (*                                                      *)
  7.         (*  Programmer:         P. Moylan                       *)
  8.         (*  Last edited:        25 July 1996                    *)
  9.         (*  Status:             Working                         *)
  10.         (*                                                      *)
  11.         (*      Could possibly be improved in terms of code     *)
  12.         (*      compactness and clarity; the present version    *)
  13.         (*      duplicates many code sections because of the    *)
  14.         (*      fact that we don't know in advance whether      *)
  15.         (*      we're dealing with a Boolean-valued result.     *)
  16.         (*                                                      *)
  17.         (********************************************************)
  18.  
  19. FROM PPMisc IMPORT
  20.     (* proc *)  StringMatch, CopyString, Message, EndOfMessage;
  21.  
  22. (************************************************************************)
  23.  
  24. TYPE
  25.     SymbolTableIndex = [0..50];
  26.     String = ARRAY [0..31] OF CHAR;
  27.     CharSet = SET OF CHAR;
  28.  
  29. CONST
  30.     AlphaNumerics = CharSet {"A".."Z", "a".."z", "0".."9"};
  31.  
  32. VAR
  33.     (* The symbol table is a table of string-valued variables.  In this *)
  34.     (* application the table is likely always to be quite small, so we  *)
  35.     (* can get away with an unsorted table and a crude linear search.   *)
  36.     (* NextEntry is the location of the first unused entry.             *)
  37.  
  38.     SymTable: ARRAY SymbolTableIndex OF
  39.                     RECORD
  40.                         sym, val: String;
  41.                     END (*RECORD*);
  42.  
  43.     NextEntry: SymbolTableIndex;
  44.  
  45. (************************************************************************)
  46. (*                        SYMBOL TABLE HANDLING                         *)
  47. (************************************************************************)
  48.  
  49. PROCEDURE LocateSymbol (VAR (*IN*) symbol: ARRAY OF CHAR;
  50.                         VAR (*OUT*) location: SymbolTableIndex): BOOLEAN;
  51.  
  52.     BEGIN
  53.         location := 0;
  54.         LOOP
  55.             IF location = NextEntry THEN
  56.                 RETURN FALSE;
  57.             END (*IF*);
  58.             IF StringMatch (symbol, SymTable[location].sym) THEN
  59.                 RETURN TRUE;
  60.             END (*IF*);
  61.             INC (location);
  62.         END (*LOOP*);
  63.     END LocateSymbol;
  64.  
  65. (************************************************************************)
  66.  
  67. PROCEDURE Lookup (VAR (*IN*) symbol: ARRAY OF CHAR;
  68.                                 VAR (*OUT*) value: ARRAY OF CHAR);
  69.  
  70.     (* Gets the value of "symbol" from the symbol table.  If the symbol *)
  71.     (* is not there, the result is the string value of "symbol" itself. *)
  72.  
  73.     VAR place: SymbolTableIndex;
  74.  
  75.     BEGIN
  76.         IF LocateSymbol (symbol, place) THEN
  77.             CopyString (SymTable[place].val, value);
  78.         ELSE
  79.             CopyString (symbol, value);
  80.         END (*IF*);
  81.     END Lookup;
  82.  
  83. (************************************************************************)
  84.  
  85. PROCEDURE DefineSymbol (VAR (*IN*) symbol: ARRAY OF CHAR;
  86.                                         value: ARRAY OF CHAR);
  87.  
  88.     (* Stores "value" as the value of variable "symbol".  The variable  *)
  89.     (* might or might not already exist in the symbol table.            *)
  90.  
  91.     VAR found: BOOLEAN;  place: SymbolTableIndex;
  92.  
  93.     BEGIN
  94.         found := LocateSymbol (symbol, place);
  95.         IF NOT found THEN
  96.             place := NextEntry;  INC(NextEntry);
  97.             CopyString (symbol, SymTable[place].sym);
  98.         END (*IF*);
  99.         CopyString (value, SymTable[place].val);
  100.     END DefineSymbol;
  101.  
  102. (************************************************************************)
  103.  
  104. PROCEDURE DumpSymbolTable;
  105.  
  106.     (* Writes the current contents of the symbol table to the screen. *)
  107.  
  108.     VAR j: SymbolTableIndex;
  109.  
  110.     BEGIN
  111.         IF NextEntry = 0 THEN
  112.             Message ("Warning: No symbols currently defined");
  113.         ELSE
  114.             Message ("LIST OF SYMBOLS CURRENTLY DEFINED");
  115.             EndOfMessage;  EndOfMessage;
  116.             FOR j := 0 TO NextEntry-1 DO
  117.                 Message ("      ");
  118.                 WITH SymTable[j] DO
  119.                     Message (sym);  Message (" = ");
  120.                     Message (val);
  121.                 END (*WITH*);
  122.                 EndOfMessage;
  123.             END (*FOR*);
  124.         END (*IF*);
  125.         EndOfMessage;
  126.     END DumpSymbolTable;
  127.  
  128. (************************************************************************)
  129. (*                        EXPRESSION EVALUATION                         *)
  130. (*                                                                      *)
  131. (* In each of the following procedures, the source string starts at     *)
  132. (* Buffer[Place], Place is updated so that on exit Buffer[Place] is the *)
  133. (* first non-alphanumeric character found.                              *)
  134. (* Note: short-circuit evaluation is NOT used, since in all cases we    *)
  135. (* want to scan to the end of the input string.                         *)
  136. (*                                                                      *)
  137. (************************************************************************)
  138.  
  139. PROCEDURE Id (VAR (*IN*) Buffer: ARRAY OF CHAR;
  140.                 VAR (*INOUT*) Place: CARDINAL;
  141.                 VAR (*OUT*) result: ARRAY OF CHAR);
  142.  
  143.     (* Picks up an alphanumeric string starting at Buffer[Place]. *)
  144.  
  145.     VAR j: CARDINAL;
  146.  
  147.     BEGIN
  148.         j := 0;
  149.         WHILE Buffer[Place] IN AlphaNumerics DO
  150.             result[j] := Buffer[Place];
  151.             INC (Place);  INC(j);
  152.         END (*WHILE*);
  153.         IF j <= HIGH(result) THEN
  154.             result[j] := CHR(0);
  155.         END (*IF*);
  156.     END Id;
  157.  
  158. (************************************************************************)
  159.  
  160. PROCEDURE EvalId (VAR (*IN*) Buffer: ARRAY OF CHAR;
  161.                 VAR (*INOUT*) Place: CARDINAL;
  162.                 VAR (*OUT*) result: ARRAY OF CHAR);
  163.  
  164.     (* Picks up and evaluates an alphanumeric string starting at        *)
  165.     (* Buffer[Place].  The difference between this procedure and Id is  *)
  166.     (* that Id returns the symbol literally, whereas this procedure     *)
  167.     (* returns the result of evaluating the string.                     *)
  168.  
  169.     VAR symbol: String;
  170.  
  171.     BEGIN
  172.         Id (Buffer, Place, symbol);
  173.         Lookup (symbol, result);
  174.     END EvalId;
  175.  
  176. (************************************************************************)
  177.  
  178. PROCEDURE Factor (VAR (*IN*) Buffer: ARRAY OF CHAR;
  179.                 VAR (*INOUT*) Place: CARDINAL): BOOLEAN;
  180.  
  181.     (* Evaluates a Boolean expression consisting of a single identifier *)
  182.     (* or an expression in parentheses.                                 *)
  183.  
  184.     VAR NOTcount: CARDINAL;  value, value2: String;  result: BOOLEAN;
  185.  
  186.     BEGIN
  187.         (* To evaluate "NOT" conditions, I can avoid recursion by       *)
  188.         (* simply waltzing my ~ until there are no more.                *)
  189.  
  190.         NOTcount := 0;
  191.         WHILE Buffer[Place] = "~" DO
  192.             INC (NOTcount);  INC(Place);
  193.         END (*WHILE*);
  194.  
  195.         (* The remaining cases we have to handle are parenthesised      *)
  196.         (* expressions, comparisons, and simple identifiers.            *)
  197.  
  198.         IF Buffer[Place] = "(" THEN
  199.             INC (Place);
  200.             result := Expr (Buffer, Place);
  201.             IF Buffer[Place] = ")" THEN
  202.                 INC (Place);
  203.             ELSE
  204.                 Message ("Error: Mismatched () in expression.");
  205.                 EndOfMessage;
  206.             END (*IF*);
  207.         ELSE
  208.             EvalId (Buffer, Place, value);
  209.             IF Buffer[Place] = "=" THEN
  210.                 INC (Place);
  211.                 EvalId (Buffer, Place, value2);
  212.             ELSIF (Buffer[Place] = "<") AND (Buffer[Place+1] = ">") THEN
  213.                 INC (Place, 2);
  214.                 EvalId (Buffer, Place, value2);
  215.                 INC (NOTcount);
  216.             ELSE
  217.                 CopyString ("TRUE", value2);
  218.             END (*IF*);
  219.             result := StringMatch (value, value2);
  220.         END (*IF*);
  221.  
  222.         IF ODD (NOTcount) THEN result := NOT result END (*IF*);
  223.         RETURN result;
  224.  
  225.     END Factor;
  226.  
  227. (************************************************************************)
  228.  
  229. PROCEDURE StringFactor (VAR (*IN*) Buffer: ARRAY OF CHAR;
  230.                 VAR (*INOUT*) Place: CARDINAL;
  231.                 VAR (*OUT*) result: ARRAY OF CHAR);
  232.  
  233.     (* Evaluates a string-valued factor starting at Buffer[Place]. *)
  234.  
  235.     VAR value2: String;
  236.  
  237.     BEGIN
  238.         IF Buffer[Place] IN AlphaNumerics THEN
  239.  
  240.             (* We have a simple Id, or a comparison. *)
  241.  
  242.             EvalId (Buffer, Place, result);
  243.             IF Buffer[Place] = "=" THEN
  244.                 INC (Place);
  245.                 EvalId (Buffer, Place, value2);
  246.                 IF StringMatch (result, value2) THEN
  247.                     CopyString ("TRUE", result);
  248.                 ELSE
  249.                     CopyString ("FALSE", result);
  250.                 END (*IF*);
  251.             ELSIF (Buffer[Place] = "<") AND (Buffer[Place+1] = ">") THEN
  252.                 INC (Place, 2);
  253.                 EvalId (Buffer, Place, value2);
  254.                 IF StringMatch (result, value2) THEN
  255.                     CopyString ("FALSE", result);
  256.                 ELSE
  257.                     CopyString ("TRUE", result);
  258.                 END (*IF*);
  259.             END (*IF*);
  260.  
  261.         ELSE
  262.  
  263.             (* It's definitely a Boolean factor. *)
  264.  
  265.             IF Factor(Buffer,Place) THEN
  266.                 CopyString ("TRUE", result);
  267.             ELSE
  268.                 CopyString ("FALSE", result);
  269.             END (*IF*);
  270.  
  271.         END (*IF*);
  272.  
  273.     END StringFactor;
  274.  
  275. (************************************************************************)
  276.  
  277. PROCEDURE Term (VAR (*IN*) Buffer: ARRAY OF CHAR;
  278.                 VAR (*INOUT*) Place: CARDINAL): BOOLEAN;
  279.  
  280.     (* Evaluates a Boolean expression consisting of one or more factors *)
  281.     (* connected by logical AND operations (indicated by "&").          *)
  282.  
  283.     VAR result: BOOLEAN;
  284.  
  285.     BEGIN
  286.         result := Factor (Buffer, Place);
  287.         WHILE Buffer[Place] = "&" DO
  288.             INC (Place);
  289.             result := Factor(Buffer,Place) AND result;
  290.         END (*WHILE*);
  291.         RETURN result;
  292.     END Term;
  293.  
  294. (************************************************************************)
  295.  
  296. PROCEDURE StringTerm (VAR (*IN*) Buffer: ARRAY OF CHAR;
  297.                 VAR (*INOUT*) Place: CARDINAL;
  298.                 VAR (*OUT*) result: ARRAY OF CHAR);
  299.  
  300.     (* Evaluates a string-valued term starting at Buffer[Place]. *)
  301.  
  302.     BEGIN
  303.         StringFactor (Buffer, Place, result);
  304.         IF Buffer[Place] = "&" THEN
  305.             INC (Place);
  306.             IF Expr(Buffer,Place) AND StringMatch(result,"TRUE") THEN
  307.                 CopyString ("TRUE", result);
  308.             ELSE
  309.                 CopyString ("FALSE", result);
  310.             END (*IF*);
  311.         END (*IF*);
  312.     END StringTerm;
  313.  
  314. (************************************************************************)
  315.  
  316. PROCEDURE Expr (VAR (*IN*) Buffer: ARRAY OF CHAR;
  317.                 VAR (*INOUT*) Place: CARDINAL): BOOLEAN;
  318.  
  319.     (* Evaluates a Boolean expression starting at Buffer[Place].        *)
  320.     (* On exit Place is updated so that Line[Place] is the first        *)
  321.     (* non-alphanumeric character found.                                *)
  322.  
  323.     VAR result: BOOLEAN;
  324.  
  325.     BEGIN
  326.         result := Term (Buffer, Place);
  327.         WHILE Buffer[Place] = "|" DO
  328.             INC (Place);
  329.             result := Term(Buffer,Place) OR result;
  330.         END (*WHILE*);
  331.         RETURN result;
  332.     END Expr;
  333.  
  334. (************************************************************************)
  335.  
  336. PROCEDURE StringExpr (VAR (*IN*) Buffer: ARRAY OF CHAR;
  337.                 VAR (*INOUT*) Place: CARDINAL;
  338.                 VAR (*OUT*) result: ARRAY OF CHAR);
  339.  
  340.     (* Evaluates a string-valued expression starting at Buffer[Place]. *)
  341.  
  342.     BEGIN
  343.         StringTerm (Buffer, Place, result);
  344.         IF Buffer[Place] = "|" THEN
  345.             INC (Place);
  346.             IF Expr(Buffer,Place) OR StringMatch(result,"TRUE") THEN
  347.                 CopyString ("TRUE", result);
  348.             ELSE
  349.                 CopyString ("FALSE", result);
  350.             END (*IF*);
  351.         END (*IF*);
  352.     END StringExpr;
  353.  
  354. (************************************************************************)
  355.  
  356. VAR s: ARRAY [0..0] OF CHAR;
  357.  
  358. BEGIN
  359.     NextEntry := 0;
  360.     s := "T";  DefineSymbol (s, "TRUE");
  361.     s := "F";  DefineSymbol (s, "FALSE");
  362. END PPExpr.
  363.  
  364.