1 MODULE Modula2PrettyPrinter;
4 Done, Read, Write, WriteLn, WriteString, OpenInput, OpenOutput,
5 CloseInput, CloseOutput;
8 ** Modula-2 Prettyprinter, November 1985.
10 ** by Ken Yap, U of Rochester, CS Dept.
12 ** Permission to copy, modify, and distribute, but not for profit,
13 ** is hereby granted, provided that this note is included.
15 ** adapted from a Pascal Program Formatter
16 ** by J. E. Crider, Shell Oil Company,
17 ** Houston, Texas 77025
19 ** This program formats Modula-2 programs according
20 ** to structured formatting principles
22 ** A valid Modula-2 program is read from the input and
23 ** a formatted program is written to the output.
24 ** It is basically a recursive descent parser with actions
25 ** intermixed with syntax scanning.
27 ** The actions of the program are as follows:
29 ** FORMATTING: Each structured statement is formatted
30 ** in the following pattern (with indentation "indent"):
32 ** XXXXXX header XXXXXXXX
38 ** where the header is one of:
40 ** IF <expression> THEN
41 ** ELSIF <expression> THEN
43 ** WHILE <expression> DO
44 ** FOR <control variable> := <FOR list> DO
45 ** WITH <RECORD variable> DO
48 ** CASE <expression> OF
51 ** and the last line begins with UNTIL or is END.
52 ** Other program parts are formatted similarly. The headers are:
54 ** <MODULE/PROCEDURE heading>;
59 ** (various FOR records AND RECORD variants)
61 ** COMMENTS: Each comment that starts before or on a specified
62 ** column on an input line (program constant "commthresh") is
63 ** copied without shifting or reformatting. Each comment that
64 ** starts after "commthresh" is reformatted and left-justified
65 ** following the aligned comment base column ("alcommbase").
67 ** SPACES AND BLANK LINES: Spaces not at line breaks are copied from
68 ** the input. Blank lines are copied from the input if they appear
69 ** between statements (or appropriate declaration units). A blank
70 ** line is inserted above each significant part of each program/
71 ** procedure if one is not already there.
73 ** CONTINUATION: Lines that are too long for an output line are
74 ** continued with additional indentation ("contindent").
79 NEWLINE = 12C; (* for Unix *)
81 maxrwlen = 15; (* size of reserved word strings *)
82 ordminchar = 0; (* ord of lowest char in char set *)
83 ordmaxchar = 127; (* ord of highest char in char set *)
84 (* The following parameters may be adjusted for the installation: *)
85 maxinlen = 255; (* maximum width of input line + 1 *)
86 maxoutlen = 80; (* maximum width of output line *)
87 tabinterval = 8; (* interval between tab columns *)
88 initmargin = 0; (* initial value of output margin *)
89 commthresh = tabinterval; (* column threshhold in input for
90 comments to be aligned *)
91 alcommbase = 40; (* aligned comments in output start
93 indent = tabinterval; (* RECOMMENDED indentation increment *)
94 contindent = tabinterval; (* continuation indentation, >indent *)
95 commindent = tabinterval; (* comment continuation indentation *)
98 natural = INTEGER[0..32767];
99 inrange = INTEGER[0..maxinlen];
100 outrange = INTEGER[0..maxoutlen];
102 errortype = (longline, noendcomm, notquote, longword, notdo, notof,
103 notend, notthen, notbegin, notuntil, notident, notsemicolon, notcolon,
104 notperiod, notparen, noeof);
106 chartype = (illegal, special, chapostrophe, chleftparen, chrightparen,
107 chperiod, digit, chcolon, chsemicolon, chlessthan, chgreaterthan,
108 letter, chleftbrace, chbar);
110 chartypeset = SET OF chartype; (* for reserved word recognition *)
112 resword = ( (* reserved words ordered by length *)
113 rwif, rwdo, rwof, rwto, rwin, rwor,
115 rwend, rwfor, rwvar, rwdiv, rwmod, rwset, rwand, rwnot, rwnil,
117 rwthen, rwelse, rwwith, rwcase, rwtype, rwloop, rwfrom,
119 rwbegin, rwelsif, rwuntil, rwwhile, rwarray, rwconst,
121 rwrepeat, rwrecord, rwmodule, rwimport, rwexport,
123 rwpointer, (* length: 7 *)
124 rwprocedure, rwqualified, (* length: 9 *)
125 rwdefinition, (* length: 10 *)
126 rwimplementation, (* length: 14 *)
127 rwx); (* length: 15 for table sentinel *)
128 rwstring = ARRAY [1..maxrwlen] OF CHAR;
130 firstclass = ( (* class of word if on new line *)
131 newclause, (* start of new clause *)
132 continue, (* continuation of clause *)
133 alcomm, (* start of aligned comment *)
134 contalcomm, (* continuation of aligned comment *)
135 uncomm, (* start of unaligned comment *)
136 contuncomm); (* continuation of unaligned comment *)
138 wordtype = RECORD (* data record for word *)
139 whenfirst : firstclass; (* class of word if on new line *)
140 puncfollows : BOOLEAN; (* to reduce dangling punctuation *)
141 blanklncount : natural; (* number of preceding blank lines *)
142 spaces : INTEGER; (* number of spaces preceding word *)
143 base : [-1..maxinlen]; (* inline.buf[base] precedes word *)
145 END; (* length of word in inline.buf *)
147 symboltype = ( (* symbols for syntax analysis *)
148 symodule, sydefinition, syimplementation, syfrom, syimport, syexport,
149 syqual, syproc, declarator, sybegin, syend, syif, sythen, syelsif,
150 syelse, syloop, sycase, syof, syuntil, syrepeat, forwhilewith, sydo,
151 syrecord, ident, intconst, semicolon, leftparen, rightparen, period,
152 colon, bar, othersym, otherword, comment, syeof);
153 symbolset = SET OF symboltype;
156 inline : RECORD (* input line data *)
157 endoffile : BOOLEAN; (* end of file on input? *)
158 ch : CHAR; (* current char, buf[index] *)
159 index : inrange; (* subscript of current char *)
160 len : natural; (* length of input line in buf *)
161 buf : ARRAY [1..maxinlen] OF CHAR;
163 outline : RECORD (* output line data *)
164 blanklns : natural; (* number of preceding blank lines *)
165 len : outrange; (* number of chars in buf *)
166 buf : ARRAY [1..maxoutlen] OF CHAR;
168 curword : wordtype; (* current word *)
169 margin : outrange; (* left margin *)
170 lnpending : BOOLEAN; (* new line before next symbol? *)
171 inheader : BOOLEAN; (* are we scanning a proc header? *)
172 symbol : symboltype; (* current symbol *)
174 (* Structured Constants *)
175 headersyms : symbolset; (* headers for program parts *)
176 strucsyms : symbolset; (* symbols that begin structured
178 stmtendsyms : symbolset; (* symbols that follow statements *)
179 stopsyms : symbolset; (* symbols that stop expression scan *)
180 recendsyms : symbolset; (* symbols that stop record scan *)
181 datawords : symbolset; (* to reduce dangling punctuation *)
182 firstrw : ARRAY [1..maxrwlen] OF resword;
183 rwword : ARRAY [rwif..rwimplementation] OF rwstring;
184 rwsy : ARRAY [rwif..rwimplementation] OF symboltype;
185 charclass : ARRAY CHAR OF chartype;
186 symbolclass : ARRAY chartype OF symboltype;
188 PROCEDURE StrCmp(a, b : rwstring) : BOOLEAN;
192 FOR i := 1 TO maxrwlen DO
200 PROCEDURE StructConsts;
201 (* establish values of structured constants *)
203 i : [ordminchar..ordmaxchar]; (* loop index *)
204 ch : CHAR; (* loop index *)
206 PROCEDURE BuildResWord(rw : resword; symword : rwstring; symbol : symboltype);
208 rwword[rw] := symword; (* reserved word string *)
209 rwsy[rw] := symbol; (* map to symbol *)
212 BEGIN (* StructConsts *)
213 (* symbol sets for syntax analysis *)
214 headersyms := symbolset{symodule, syproc, declarator, sybegin, syend,
216 strucsyms := symbolset{sycase, syrepeat, syif, forwhilewith, syloop};
217 stmtendsyms := symbolset{semicolon, bar, syend, syuntil, syelsif,
219 stopsyms := headersyms + strucsyms + stmtendsyms;
220 recendsyms := symbolset{rightparen, syend, syeof};
221 datawords := symbolset{otherword, intconst, ident, syend};
223 (* constants for recognizing reserved words *)
224 firstrw[1] := rwif; (* length: 1 *)
225 firstrw[2] := rwif; (* length: 2 *)
226 BuildResWord(rwif, 'IF ', syif);
227 BuildResWord(rwdo, 'DO ', sydo);
228 BuildResWord(rwof, 'OF ', syof);
229 BuildResWord(rwto, 'TO ', othersym);
230 BuildResWord(rwin, 'IN ', othersym);
231 BuildResWord(rwor, 'OR ', othersym);
232 firstrw[3] := rwend; (* length: 3 *)
233 BuildResWord(rwend, 'END ', syend);
234 BuildResWord(rwfor, 'FOR ', forwhilewith);
235 BuildResWord(rwvar, 'VAR ', declarator);
236 BuildResWord(rwdiv, 'DIV ', othersym);
237 BuildResWord(rwmod, 'MOD ', othersym);
238 BuildResWord(rwset, 'SET ', othersym);
239 BuildResWord(rwand, 'AND ', othersym);
240 BuildResWord(rwnot, 'NOT ', othersym);
241 BuildResWord(rwnil, 'NIL ', otherword);
242 firstrw[4] := rwthen; (* length: 4 *)
243 BuildResWord(rwthen, 'THEN ', sythen);
244 BuildResWord(rwelse, 'ELSE ', syelse);
245 BuildResWord(rwwith, 'WITH ', forwhilewith);
246 BuildResWord(rwloop, 'LOOP ', syloop);
247 BuildResWord(rwfrom, 'FROM ', syfrom);
248 BuildResWord(rwcase, 'CASE ', sycase);
249 BuildResWord(rwtype, 'TYPE ', declarator);
250 firstrw[5] := rwbegin; (* length: 5 *)
251 BuildResWord(rwbegin, 'BEGIN ', sybegin);
252 BuildResWord(rwelsif, 'ELSIF ', syelsif);
253 BuildResWord(rwuntil, 'UNTIL ', syuntil);
254 BuildResWord(rwwhile, 'WHILE ', forwhilewith);
255 BuildResWord(rwarray, 'ARRAY ', othersym);
256 BuildResWord(rwconst, 'CONST ', declarator);
257 firstrw[6] := rwrepeat; (* length: 6 *)
258 BuildResWord(rwrepeat, 'REPEAT ', syrepeat);
259 BuildResWord(rwrecord, 'RECORD ', syrecord);
260 BuildResWord(rwmodule, 'MODULE ', symodule);
261 BuildResWord(rwimport, 'IMPORT ', syimport);
262 BuildResWord(rwexport, 'EXPORT ', syexport);
263 firstrw[7] := rwpointer; (* length: 7 *)
264 BuildResWord(rwpointer, 'POINTER ', othersym);
265 firstrw[8] := rwprocedure; (* length: 8 *)
266 firstrw[9] := rwprocedure; (* length: 9 *)
267 BuildResWord(rwprocedure, 'PROCEDURE ', syproc);
268 BuildResWord(rwqualified, 'QUALIFIED ', syqual);
269 firstrw[10] := rwdefinition; (* length: 10 *)
270 BuildResWord(rwdefinition, 'DEFINITION ', sydefinition);
271 firstrw[11] := rwimplementation;(* length: 11 *)
272 firstrw[12] := rwimplementation;(* length: 12 *)
273 firstrw[13] := rwimplementation;(* length: 13 *)
274 firstrw[14] := rwimplementation;(* length: 14 *)
275 BuildResWord(rwimplementation, 'IMPLEMENTATION ', syimplementation);
276 firstrw[15] := rwx; (* length: 15 FOR table sentinel *)
278 (* constants for lexical scan *)
279 FOR i := ordminchar TO ordmaxchar DO
280 charclass[CHR(i)] := illegal;
282 FOR ch := 'a' TO 'z' DO
283 charclass[ch] := letter;
284 charclass[CAP(ch)] := letter;
286 FOR ch := '0' TO '9' DO
287 charclass[ch] := digit;
289 charclass[' '] := special;
290 charclass['"'] := chapostrophe;
291 charclass['#'] := special;
292 charclass['&'] := special;
293 charclass["'"] := chapostrophe;
294 charclass['('] := chleftparen;
295 charclass[')'] := chrightparen;
296 charclass['*'] := special;
297 charclass['+'] := special;
298 charclass[','] := special;
299 charclass['-'] := special;
300 charclass['.'] := chperiod;
301 charclass['/'] := special;
302 charclass[':'] := chcolon;
303 charclass[';'] := chsemicolon;
304 charclass['<'] := chlessthan;
305 charclass['='] := special;
306 charclass['>'] := chgreaterthan;
307 charclass['@'] := special;
308 charclass['['] := special;
309 charclass[']'] := special;
310 charclass['^'] := special;
311 charclass['{'] := special;
312 charclass['|'] := chbar;
313 charclass['}'] := special;
314 symbolclass[illegal] := othersym;
315 symbolclass[special] := othersym;
316 symbolclass[chapostrophe] := otherword;
317 symbolclass[chleftparen] := leftparen;
318 symbolclass[chrightparen] := rightparen;
319 symbolclass[chperiod] := period;
320 symbolclass[digit] := intconst;
321 symbolclass[chcolon] := colon;
322 symbolclass[chsemicolon] := semicolon;
323 symbolclass[chlessthan] := othersym;
324 symbolclass[chgreaterthan] := othersym;
325 symbolclass[chbar] := bar;
326 symbolclass[letter] := ident;
329 (* FlushLine/WriteError/ReadLine convert between files and lines. *)
332 (* Write buffer into output file *)
334 i, j, vircol : outrange; (* loop index *)
335 nonblankseen : BOOLEAN;
338 WHILE blanklns > 0 DO
340 blanklns := blanklns - 1;
344 nonblankseen := FALSE;
345 (* set this to TRUE if you don't want
346 blanks to tab conversion *)
347 FOR i := 0 TO len - 1 DO
348 IF buf[i+1] <> ' ' THEN
349 IF NOT nonblankseen THEN
361 nonblankseen := TRUE;
364 vircol := vircol + 1;
376 PROCEDURE WriteError(error : errortype; nm : ARRAY OF CHAR);
377 (* report error to output *)
379 i, ix : inrange; (* loop index, limit *)
382 WriteString('(* !!! error, ');
386 WriteString('shorter line');
388 WriteString('END OF comment');
390 WriteString("final ' on line");
392 WriteString('shorter word');
398 WriteString('"END"');
400 WriteString('"THEN"');
402 WriteString('"BEGIN"');
404 WriteString('"UNTIL"');
406 WriteString('"identifier"');
416 WriteString('END OF file');
418 WriteString(' expected');
419 IF error >= longword THEN
420 WriteString(', NOT "');
423 IF size > maxrwlen THEN
429 Write(buf[base + i]);
435 IF error = noeof THEN
436 WriteString(', FORMATTING STOPS');
438 WriteString(' !!! *)');
443 (* Read line into input buffer *)
445 c : CHAR; (* input character *)
458 IF c < ' ' THEN (* convert ISO control chars (except
459 leading form feed) to spaces *)
463 (* add last space at end *)
464 WHILE len MOD 8 <> 7 DO
466 IF len < maxinlen THEN
470 (* END tab handling *)
471 ELSIF (c <> FF) OR (len > 0) THEN
474 END; (* END ISO control char conversion *)
476 IF len < maxinlen THEN
480 IF NOT endoffile THEN
481 IF len >= maxinlen THEN
482 (* input line too long *)
483 WriteError(longline, "(ReadLine), ");
486 WHILE (len > 0) AND (buf[len] = ' ') DO
490 len := len + 1; (* add exactly ONE trailing blank *)
497 (* get next char from input buffer *)
505 PROCEDURE NextChar() : CHAR;
506 (* look at next char in input buffer *)
508 RETURN inline.buf[inline.index + 1];
511 PROCEDURE StartWord(startclass : firstclass);
512 (* note beginning of word, and count preceding lines and spaces *)
514 first : BOOLEAN; (* is word the first on input line? *)
519 whenfirst := startclass;
521 WHILE (index >= len) AND NOT endoffile DO
523 blanklncount := blanklncount + 1;
525 IF startclass = contuncomm THEN
531 (* with exactly ONE trailing blank *)
540 spaces := 0; (* count leading spaces *)
541 IF NOT endoffile THEN
543 spaces := spaces + 1;
555 PROCEDURE FinishWord;
556 (* note end of word *)
560 puncfollows := (symbol IN datawords) AND (ch <> ' ');
561 size := index - base - 1;
566 PROCEDURE CopyWord(newline : BOOLEAN; pword : wordtype);
567 (* copy word from input buffer into output buffer *)
569 i : INTEGER; (* outline.len excess, loop index *)
573 i := maxoutlen - len - spaces - size;
574 IF newline OR (i < 0) OR ((i = 0) AND puncfollows) THEN
577 IF len = 0 THEN (* first word on output line *)
578 blanklns := blanklncount;
580 (* update LOCAL word.spaces *)
586 spaces := alcommbase;
588 spaces := alcommbase + commindent;
592 (* spaces := spaces *);
594 IF spaces + size > maxoutlen THEN
595 spaces := maxoutlen - size;
605 FOR i := 1 TO spaces DO
610 FOR i := 1 TO size DO
611 (* copy actual word *)
613 buf[len] := inline.buf[base + i];
619 PROCEDURE DoComment; (* copy aligned or unaligned comment *)
621 PROCEDURE CopyComment(commclass : firstclass; commbase : inrange);
622 (* copy words of comment *)
624 endcomment : BOOLEAN; (* end of comment? *)
626 WITH curword DO (* copy comment begin symbol *)
627 whenfirst := commclass;
628 spaces := commbase - outline.len;
629 CopyWord((spaces < 0) OR (blanklncount > 0), curword);
631 commclass := VAL(firstclass, ORD(commclass)+1);
633 REPEAT (* loop for successive words *)
634 StartWord(commclass);
635 endcomment := endoffile;
638 WriteError(noendcomm, "(CopyComment), ")
650 UNTIL (ch = ' ') OR endcomment;
653 CopyWord(FALSE, curword)
658 BEGIN (* DoComment *)
659 IF curword.base < commthresh THEN
660 (* copy comment without alignment *)
661 CopyComment(uncomm, curword.base)
662 ELSE (* align AND format comment *)
663 CopyComment(alcomm, alcommbase);
668 (* get next non-comment symbol *)
670 PROCEDURE CopySymbol(symbol : symboltype; pword : wordtype);
671 (* copy word(s) of symbol *)
673 IF symbol = comment THEN
674 DoComment; (* NOTE: DoComment uses global word! *)
676 ELSIF symbol = semicolon THEN
677 CopyWord(FALSE, pword);
678 lnpending := NOT inheader;
680 CopyWord(lnpending, pword);
685 PROCEDURE FindSymbol;
686 (* find next symbol in input buffer *)
689 termch : CHAR; (* string terminator *)
690 chclass : chartype; (* classification of leading char *)
692 PROCEDURE CheckResWord;
693 (* check if current identifier is reserved word/symbol *)
695 rw, rwbeyond : resword; (* loop index, limit *)
696 symword : rwstring; (* copy of symbol word *)
697 i : [-1..maxrwlen]; (* loop index *)
701 size := index - base - 1;
702 IF size < maxrwlen THEN
704 FOR i := 1 TO size DO
705 symword[i] := CAP(buf[ base + i]);
708 rwbeyond := firstrw[size + 1];
711 IF rw >= rwbeyond THEN
713 ELSIF StrCmp(symword, rwword[rw]) THEN
716 rw := VAL(resword,ORD(rw)+1);
718 UNTIL symbol <> semicolon;
720 whenfirst := newclause;
727 WHILE charclass[inline.ch] IN chartypeset{letter, digit} DO
736 WHILE charclass[ch] = digit DO
740 IF charclass[NextChar()] = digit THEN
741 (* NOTE: NextChar is a function! *)
744 WHILE charclass[ch] = digit DO
749 IF CAP(ch) = 'E' THEN
752 IF (ch = '+') OR (ch = '-') THEN
755 WHILE charclass[ch] = digit DO
762 PROCEDURE GetStringLiteral;
764 endstring : BOOLEAN; (* end of string literal? *)
772 ELSIF index >= len THEN
773 (* error, final "'" not on line *)
774 WriteError(notquote, "(GetStringLiteral), ");
781 END GetStringLiteral;
783 BEGIN (* FindSymbol *)
789 termch := ch; (* save for string literal routine *)
790 chclass := charclass[ch];
791 symbol := symbolclass[chclass];
792 GetChar; (* second CHAR *)
794 chsemicolon, chrightparen, chleftbrace, special,
808 IF (ch = '=') OR (ch = '>') THEN
824 END; (* Added by me (CJ): *)
829 END; (* FindSymbol *)
832 BEGIN (* GetSymbol *)
834 CopySymbol(symbol, curword);
835 (* copy word for symbol to output *)
836 FindSymbol (* get next symbol *)
837 UNTIL symbol <> comment;
840 PROCEDURE StartClause;
841 (* (this may be a simple clause, or the start of a header) *)
843 curword.whenfirst := newclause;
847 PROCEDURE PassSemicolons;
848 (* pass consecutive semicolons *)
850 WHILE symbol = semicolon DO
857 (* finish header, start body of structure *)
860 margin := margin + indent;
863 PROCEDURE FinishBody;
866 margin := margin - indent;
869 PROCEDURE PassPhrase(finalsymbol : symboltype);
870 (* process symbols until significant symbol encountered *)
872 endsyms : symbolset; (* complete set of stopping symbols *)
874 IF symbol <> syeof THEN
876 INCL(endsyms, finalsymbol);
879 UNTIL symbol IN endsyms;
883 PROCEDURE Expect(expectedsym : symboltype; error : errortype; syms : symbolset;
885 (* fail if current symbol is not the expected one, then recover *)
887 IF symbol = expectedsym THEN
890 WriteError(error, nm);
891 INCL(syms, expectedsym);
892 WHILE NOT (symbol IN syms) DO
895 IF symbol = expectedsym THEN
902 (* process heading for program or procedure *)
904 PROCEDURE MatchParens; (* process parentheses in heading *)
909 WHILE NOT (symbol IN recendsyms) DO
910 IF symbol = leftparen THEN
916 endsyms := stopsyms + recendsyms;
917 Expect(rightparen, notparen, endsyms, "(MatchParens), ");
922 PassPhrase(leftparen);
923 IF symbol = leftparen THEN
928 IF symbol = colon THEN
929 PassPhrase(semicolon);
931 Expect(semicolon, notsemicolon, stopsyms, "(Heading), ");
936 (* process record declaration *)
942 Expect(syend, notend, recendsyms, "(DoRecord), ");
946 (* process (case) variant part *)
949 Expect(syof, notof, stopsyms, "(Dovariant), ");
955 PROCEDURE DoParens(forvariant : BOOLEAN);
956 (* process parentheses in record *)
963 lnpending := FALSE; (* for empty field list *)
964 Expect(rightparen, notparen, recendsyms, "(DoParens), ");
970 PROCEDURE PassFields(forvariant : BOOLEAN);
971 (* process declarations *)
973 WHILE NOT (symbol IN recendsyms) DO
974 IF symbol = semicolon THEN
976 ELSIF symbol = syrecord THEN
978 ELSIF symbol = sycase THEN
980 ELSIF symbol = leftparen THEN
989 (* process statement *)
994 Expect(syend, notend, stmtendsyms, "(Case), ");
997 Expect(syend, notend, stmtendsyms, "(If), ");
1000 Expect(syend, notend, stmtendsyms, "(Loop), ");
1004 ForWhileWithStatement;
1005 Expect(syend, notend, stmtendsyms, "(ForWhileWith), ");
1008 | semicolon: ; (*!!! Added by me (CJ) *)
1013 PROCEDURE AssignmentProccall;
1014 (* pass an assignment statement or procedure call *)
1016 WHILE NOT (symbol IN stmtendsyms) DO
1019 END AssignmentProccall;
1021 PROCEDURE StatementSequence;
1022 (* process sequence of statements *)
1026 IF symbol <> semicolon THEN
1032 END StatementSequence;
1034 PROCEDURE IfStatement;
1035 (* process if statement *)
1038 Expect(sythen, notthen, stopsyms, "(Ifstatement), ");
1042 WHILE symbol = syelsif DO
1045 Expect(sythen, notthen, stopsyms, "(Elseif), ");
1046 StartBody; (* new line after 'THEN' *)
1050 IF symbol = syelse THEN
1053 StartBody; (* new line after 'ELSE' *)
1059 PROCEDURE CaseStatement;
1060 (* process case statement *)
1063 Expect(syof, notof, stopsyms, "(caseStatement), ");
1066 WHILE symbol = bar DO
1070 IF symbol = syelse THEN
1079 (* process one case clause *)
1081 IF NOT (symbol IN symbolset{bar, syelse}) THEN
1083 Expect(colon, notcolon, stopsyms, "(OneCase), ");
1084 StartBody; (* new line, indent after colon *)
1086 FinishBody; (* left-indent after case *)
1090 PROCEDURE RepeatStatement;
1091 (* process repeat statement *)
1094 StartBody; (* new line, indent after 'REPEAT' *)
1096 FinishBody; (* left-ident after UNTIL *)
1097 StartClause; (* new line before UNTIL *)
1098 Expect(syuntil, notuntil, stmtendsyms, "(repeatstatement), ");
1099 PassPhrase(semicolon);
1100 END RepeatStatement;
1102 PROCEDURE LoopStatement;
1103 (* process loop statement *)
1106 StartBody; (* new line, indent after LOOP *)
1108 FinishBody; (* left-ident before END *)
1111 PROCEDURE ForWhileWithStatement;
1112 (* process for, while, or with statement *)
1115 Expect(sydo, notdo, stopsyms, "(ForWhileWithstatement), ");
1119 END ForWhileWithStatement;
1121 PROCEDURE ProcedureDeclaration;
1122 (* pass a procedure declaration *)
1126 Expect(ident, notident, stmtendsyms, "(Proceduredeclaration)1, ");
1127 Expect(semicolon, notsemicolon, stmtendsyms,
1128 "(Proceduredeclaration)2, ");
1129 END ProcedureDeclaration;
1131 PROCEDURE ProcedureHeading;
1135 END ProcedureHeading;
1139 WHILE symbol IN symbolset{declarator, symodule, syproc} DO
1142 IF symbol = sybegin THEN
1148 Expect(syend, notend, stmtendsyms, "(Block), ");
1151 PROCEDURE Declaration;
1153 IF symbol = declarator THEN
1154 StartClause; (* CONST, TYPE, VAR *)
1158 PassPhrase(syrecord);
1159 IF symbol = syrecord THEN
1162 IF symbol = semicolon THEN
1165 UNTIL symbol IN headersyms;
1167 ELSIF symbol = symodule THEN
1169 ELSIF symbol = syproc THEN
1170 ProcedureDeclaration;
1174 PROCEDURE ModuleDeclaration;
1176 PassPhrase(semicolon);
1178 WHILE symbol IN symbolset{syimport, syexport, syfrom} DO
1182 Expect(ident, notident, stmtendsyms, "(ModuleDeclaration), ");
1183 END ModuleDeclaration;
1185 PROCEDURE ImportExport;
1187 IF symbol = syfrom THEN
1188 PassPhrase(syimport);
1190 IF symbol = syimport THEN
1192 ELSIF symbol = syexport THEN
1194 IF symbol = syqual THEN
1199 PassPhrase(semicolon);
1204 PROCEDURE OneDefinition;
1206 IF symbol = declarator THEN
1208 ELSIF symbol = syproc THEN
1213 PROCEDURE DefinitionModule;
1216 PassPhrase(semicolon);
1218 WHILE symbol IN symbolset{syimport, syexport, syfrom} DO
1221 WHILE symbol IN symbolset{declarator, syproc} DO
1224 Expect(syend, notend, stmtendsyms, "DefinitionModule1, " );
1226 Expect(period, notperiod, stmtendsyms, 'DefintionModule2, ');
1227 END DefinitionModule;
1229 PROCEDURE ProgramModule;
1232 Expect(period, notperiod, stmtendsyms, "ProgramModule, ");
1235 PROCEDURE CompilationUnit;
1237 IF symbol = syimplementation THEN
1240 ELSIF symbol = sydefinition THEN
1245 END CompilationUnit;
1247 PROCEDURE CopyRemainder;
1248 (* copy remainder of input *)
1250 WriteError(noeof, "(Copyremainder), ");
1253 CopyWord(FALSE, curword);
1254 StartWord(contuncomm);
1255 IF NOT endoffile THEN
1265 PROCEDURE Initialize;
1266 (* initialize global variables *)
1279 whenfirst := contuncomm;
1280 puncfollows := FALSE;
1286 margin := initmargin;
1295 (* Files may be opened here. *)
1300 IF NOT inline.endoffile THEN
1306 END Modula2PrettyPrinter.