home *** CD-ROM | disk | FTP | other *** search
/ Power Programming / powerprogramming1994.iso / progtool / microcrn / issue_34.arc / CAPITALZ.FIG < prev    next >
Text File  |  1987-01-07  |  12KB  |  290 lines

  1. (( This is Capitalization Figure 2 -- Modifications To EDITCONTROL 
  2. Modules ))
  3.  
  4. (* THESE GO JUST BEFORE THE INITIALIZATION SECTION, NEAR THE END *)
  5.  
  6. PROCEDURE Scan;  (* Capitalizes keywords and autoindents next line *)
  7. BEGIN
  8.         scan(CurFilePtr^,TRUE);(* CAP the keywords in the file *)
  9.         RedoLine;              (* update the displayed line    *)
  10.         InsOneChar(CR);        (* put in a CR                  *)
  11.         scan(CurFilePtr^,TRUE);(* put the intro in the file    *)
  12.         RedoLine;              (* update the displayed line    *)
  13.         END Scan;               
  14. PROCEDURE AutoIndent; (* Autoindents next line *)
  15. BEGIN
  16.         scan(CurFilePtr^,FALSE);(* Get the intro for the line  *)
  17.         InsOneChar(CR);         (* put in a CR                 *)
  18.         scan(CurFilePtr^,FALSE);(* put the intro in the file   *)
  19.         RedoLine;               (* update the displayed line   *)
  20.         END AutoIndent;
  21.  
  22. ((********************************************************************))
  23.  
  24. (( This is Capitalization Figure 4 -- The New Module Implementation ))
  25.  
  26.  
  27. IMPLEMENTATION MODULE Scanner;
  28.  
  29. (* based on the FSM approach given by Gary A. Ford and Richard S. Wiener,
  30.    MODULA-2 A SOFTWARE DEVELOPMENT APPROACH, Wiley, 1985, page 350 *)
  31.  
  32. FROM MakeEdits IMPORT EditFile, DelChars, InsChars, BackOneChar,
  33.                      ForwardOneChar, GetCurrentChar;
  34. ;
  35. CONST
  36.    bufsize   = 15;   (* Max length for Modula-2 'symbol' *)
  37.    introsize = 40;   (* Half screen width - to allow 40 spaces and/or tabs *)
  38.    LF        = 0ax;  (* Last character in EOL marker in file *) 
  39.    SPACE     = 20x;  (* White space characters *)
  40.    TAB       = 09x;
  41.    
  42. TYPE
  43.    (* These are the states of the Finite State Machine *)
  44.    states   = (start, insym, instr, incom, encom, excom);
  45.    barray   = ARRAY [1 .. bufsize] OF CHAR; 
  46.    iarray   = ARRAY [1 .. introsize] OF CHAR;
  47.    CHARSET  = SET OF CHAR;
  48.  
  49. VAR (* all variables are global in this module *)
  50.    state    : states;  (* state of FSM *)
  51.    ch       : CHAR;    (* current character in buffer *)
  52.    delim    : CHAR;    (* holds string delimiter *) 
  53.    buffer   : barray;  (* symbol buffer *)
  54.    intro    : iarray;  (* intro buffer  *)
  55.    buflen   : CARDINAL;(* number of characters in symbol *)
  56.    introlen : CARDINAL;(* number of characters in intro to line *)
  57.    j,k,l    : CARDINAL;(* counters for various loops *)
  58.    symset   : CHARSET; (* the set of characters used in symbols *)
  59.    flag,sec : BOOLEAN; (* flag is gnl purpose BOOLEAN, sec is for pass *)
  60.    sp : ARRAY [2 .. 15] OF CARDINAL;(* Array of indexes into the CHAR array *)
  61.    a2 : ARRAY [0 .. 13] OF CHAR;  (* this is really one big CHAR array *)
  62.    a3 : ARRAY [0 .. 57] OF CHAR;  (* but there is no easy way to do    *)
  63.    a4 : ARRAY [0 .. 75] OF CHAR;  (* initialization on any array of    *)
  64.    a5 : ARRAY [0 .. 49] OF CHAR;  (* 350+ characters - so I do it on   *)
  65.    a6 : ARRAY [0 .. 41] OF CHAR;  (* ten smaller arrays. Obviously this*)
  66.    a7 : ARRAY [0 .. 35] OF CHAR;  (* requires that bounds checking be  *)
  67.    a8 : ARRAY [0 .. 15] OF CHAR;  (* turned off and that arrays be     *)
  68.    a9 : ARRAY [0 .. 17] OF CHAR;  (* be stored contiguously in memory. *)
  69.    a10: ARRAY [0 .. 29] OF CHAR;
  70.    a14: ARRAY [0 .. 15] OF CHAR;
  71.  
  72. PROCEDURE scan(VAR f:EditFile; full:BOOLEAN);
  73. (*
  74.    This procedure alternates between scanning a line and writing the
  75.    intro from the line just scanned - IF full THEN auto capitalization
  76.    is performed as part of the first pass. ELSE the first pass just
  77.    gets the intro string for use on the second pass. f is the file
  78.    being edited.
  79. *)
  80.  
  81. PROCEDURE check ():BOOLEAN;
  82. (* 
  83.   this procedure checks a symbol to see if it should be capitalized
  84. *)
  85.  
  86. BEGIN
  87.    flag := FALSE;   (* will be set true if match on all characters *)
  88. (* Put a marker after the end of the symbol to stop comparison *)
  89.    buffer[buflen+1] := '!';
  90. (* Then point to array position corresponding to buffer length *)
  91.    k := sp[buflen];
  92. (* Now scan all entries of that length for a match on all characters *)
  93.    LOOP
  94.       l := 0;
  95.       WHILE a2[k+l] = buffer[l+1] DO l := l+1 END;
  96. (* If a match on all characters is found then return TRUE *)
  97.       IF l = buflen THEN
  98.          flag := TRUE;
  99.          EXIT;
  100.       END 
  101.       k := k + buflen;
  102. (* Else if all keywords of that length checked then return FALSE *)
  103.       IF k >= sp[buflen+1] THEN EXIT END;
  104.    END 
  105.    RETURN flag
  106. END check;
  107.  
  108. BEGIN (* PROCEDURE scan *)
  109. (*
  110.    The BOOLEAN sec keeps track of which pass we are on.
  111. *)
  112.    sec := NOT sec;
  113.    IF sec THEN         (* second pass *)
  114.       IF introlen > 0 THEN InsChars(f,intro,introlen) END;
  115.    ELSE                (* first pass  *)
  116. (*
  117.    Place a marker in file - to mark current position and to make sure
  118.    that all lines ending with a symbol return to the start state.
  119. *)
  120.    intro[1]:=20x;
  121.    intro[2]:=00x;      
  122.    InsChars(f,intro,2);(* use procedure InsChars from MakeEdits *)
  123. (*
  124.    Move back to beginning of line.
  125. *)
  126.    WHILE BackOneChar(f) AND (GetCurrentChar(f) # LF) DO END;
  127.    introlen := 0;
  128. (*
  129.    IF NOT BEGINNING OF FILE THEN move forward to first character of line.
  130.    IF BOF THEN we are already on the first character of the line.
  131. *)
  132.    ch := GetCurrentChar(f);
  133.    IF ch = LF THEN
  134.       flag := ForwardOneChar(f);
  135.       ch := GetCurrentChar(f)
  136.    END;
  137. (*
  138.  Now we save the intro to the line ( white space )
  139. *)
  140.    WHILE ((ch = SPACE) OR ( ch = TAB)) AND (introlen < introsize) DO
  141.       INC (introlen);
  142.       intro[introlen] := ch;
  143.       flag := ForwardOneChar(f);
  144.       ch := GetCurrentChar(f)
  145.    END; (* WHILE *)
  146. (*
  147.   There are two possibilities on first pass: if not full then 
  148.    we just get the intro. If full we also do capitalization.
  149. *)
  150.    IF full THEN
  151.       buflen:=0;          (* Initialize symbol buffer *)
  152.       state := start;     (* and state of FSM *)
  153.       WHILE (ch # 00x) DO (* Now process line until end marker is found *)
  154. (*
  155.   This is basically Ford and Weiner's FSM, but without handling of nested 
  156.   comments - their design processes a file, this one just does a line.
  157.  *)
  158.          CASE state OF
  159.          start :
  160.             CASE ch OF
  161.                'a' .. 'z' : 
  162. (*
  163.    There are three ways to exit the start state; ecountering a symbol,
  164.     ecountering a comment, or ecountering a string. If a letter is
  165.     encountered,it starts a symbol. We go to the insym(bol) state.
  166. *)
  167.                             state := insym;
  168. (* Symbols are stored in buffer for comparison to the keywords *)
  169.                             INC(buflen);
  170.                             buffer[buflen] := ch;
  171.                 |
  172. (*
  173.    An open paren may be the start of a comment, state is en(tering)com(ment).
  174. *)
  175.                 '('       : state := encom;
  176.                 |
  177. (*
  178.    A single or double quote is the start of a string literal.
  179.    The new state is instr(ing). We must record the delimiter.
  180. *)
  181.                 '"',"'"   : state := instr;
  182.                             delim := ch;
  183.             END |
  184.          insym :
  185. (*
  186.    When we are in a symbol, we continue as long as the characters
  187.    encountered are lowercase letters - we do not allow mixed case
  188.    or digits. Each letter is stored in the buffer.
  189. *)
  190.           IF (ch IN symset) AND (buflen < 14 ) THEN 
  191.                 INC(buflen);
  192.                 buffer[buflen] := ch;
  193. (*
  194.    When a character other than a letter is encountered, we check to see if
  195.    the symbol in the buffer is in our table. If it is we CAP the symbol in
  196.    the file. The function BackOneChar and the procedures DelChars and 
  197.    InsChars used for this process are from the module MakeEdits.
  198. *)
  199.            ELSIF (buflen > 1) AND (check()) THEN
  200.                 FOR j := 1 TO buflen DO       (* move back thru file  *)
  201.                    flag := BackOneChar(f);    (* flag is just a dummy *)
  202.                    buffer[j] := CAP(buffer[j])(* CAP the buffer too   *)
  203.                 END;
  204.                 DelChars(f,buflen);           (* remove the symbol    *)
  205.                 InsChars(f,buffer,buflen);    (* and replace it       *)
  206.                 buflen := 0;                  (* reset for next symbol*)
  207.                 state := start;               (* back to start state  *)
  208. (* If the symbol is not in the table then we leave the file alone *)
  209.            ELSE 
  210.                 buflen := 0;                  (* reset for next symbol*)
  211.                 state := start;               (* back to start state  *)
  212.            END |
  213.          instr :
  214. (* When in a string we just watch for the string delimiter *)
  215.             IF ch = delim THEN
  216.                state := start;
  217.             END |
  218.          encom :
  219. (*
  220.    When en(tering)com(ment) we go to incom(ment) if the next character
  221.    is '*', instr if the next character is a delimiter, and insym if it
  222.    is in symset, else back to start.
  223. *)
  224.            IF ch = '*' THEN
  225.              state := incom;
  226.            ELSIF (ch =  "'") OR (ch = '"') THEN
  227.              state  := instr;
  228.              delim := ch;
  229.            ELSIF (ch IN symset) THEN
  230.              state := insym;
  231.              INC(buflen);
  232.              buffer[buflen] := ch;
  233.            ELSE 
  234.              state := start;
  235.            END |
  236.          incom :
  237. (* When in comment we watch for '*', new sate is  ex(iting)com(ment) *)
  238.             IF ch = '*' THEN
  239.                state := excom;
  240.             END |
  241.          excom :
  242. (* When exiting a comment we must find ')' for the new state to be start *) 
  243.             IF ch = ')' THEN
  244.                state := start;
  245.             ELSE
  246.                state := incom;
  247.             END
  248.          END (* CASE *)  
  249. (* Get the next character to process *) 
  250.          flag := ForwardOneChar(f);
  251.          ch := GetCurrentChar(f);
  252.       END (* WHILE *)
  253.    ELSE (* NOT full *)
  254. (* If we are only getting intro we must skip over the rest of the line *)
  255.       WHILE (GetCurrentChar(f) # 00x) AND ForwardOneChar(f) DO END;
  256.    END (* IF *)
  257. (* Finally, we remove the marker we inserted at the end of the line *)
  258.       flag := BackOneChar(f);   (* We are on second character *)
  259.       DelChars(f,2);            (* Remove both characters *)
  260.    END (* IF *)
  261. END scan;
  262.    
  263. BEGIN   (* initialization of data structures used by scan *)
  264.    symset := CHARSET{'a' .. 'z'}; (* only lower case will be considered *)
  265.    a2 := 'bydoifinoforto';
  266.    a3 := 'absadrandcapchrdecdivendforincmodnewnilnotoddordsetvarval ';
  267.    a4 := 'bytecasecharelseexclexitfromhalthighinclloopprocrealsizethentruetypewithword';
  268.    a5 := 'arraybeginconstelsiffalsefloattrunctsizeuntilwhile';
  269.    a6 := 'exportimportmodulerecordrepeatreturnsystem';
  270.    a7 := 'booleandisposeintegerpointerprocess ';
  271.    a8 := 'cardinaltransfer';
  272.    a9 := 'procedurequalified';
  273.    a10 :='definitioniotransfernewprocess';
  274.    a14 :='implementation  ';
  275.    (* These are the positions 'within' a2 where each of the above arrays 
  276.       start. This is used to shorten the search by only searching that
  277.       part of the table which contains entries of the same length as the
  278.       symbol. These positions are correct if the arrays are stored adjacent
  279.       to each other in the order they were declared. The arrays all have
  280.       an even number of bytes. This allows the same declaration to work
  281.       on a Z80 ( byte aligned variables ) and a 68000 ( word aligned ).
  282.       I think it should work on other 16 bit processors as well, but I
  283.       haven't tried it. *)
  284.    sp[2] := 0; sp[3] := 14; sp[4] := 72; sp[5] := 148;
  285.    sp[6] := 198; sp[7] := 240; sp[8] := 276; sp[9] := 292;
  286.    sp[10] := 310; sp[11] := 354; sp[12] := 354; sp[13] := 354;
  287.    sp[14] := 340; sp[15] := 354;
  288.    sec := TRUE; (* set it up to start on first pass *)
  289. END Scanner.
  290.