-*-Text-*-  File: EPASC Node: Top Up: (EMACS)Top Next: Available PASCAL mode in EMACS provides support for inputing and editing Pascal code. You should be in Pascal Mode automatically when you edit a Pascal file. You can call it directly by loading the Pascal library (M-X Load Library Pascal ) and giving the command M-X Pascal Mode. * Menu: * Available:: List of all special commands. * Compile:: Macros for hopping right to your compiler errors. * Variables:: Synopsis of the customization variables. * Indent:: Indenting old and new lines of code. * Statements:: Inserting complete structured statements. * Comments:: Things you can do with comments in PASCAL mode. * Paren Groups:: Commands which manipulate parenthesized expressions. * Hints:: Other commands useful for editing Pascal code. * Hacker:: Information for hackers or the very interested.  Node: Available, Previous: Top, Next: Compile, Up: Top Commands which start on keys: C-M-I The main indentation driver, described under Indent. LINEFEED Does a CRLF, then a C-M-I. Useful at the ends of lines. C-M-? Explains the last indentation, if you're curious. C-M-\,C-M-G,M-G Indent Pascal Region (re-indent all lines in region) Rubout TAB-hacking Rubout (converts TABs to spaces). C-Rubout Normal Rubout. M-; Start comment at end of line. *note comments: comments. C-M-* Insert a comment right here (don't re-indent) C-M-$ Global Pascal Comment C-M-N Forward over a BEGIN/END (or REPEAT/UNTIL etc.) pair. C-M-P Backward over a BEGIN/END pair. C-M-H Mark Procedure C-M-. Prefix for Structured Insert Commands. *note: St: Statements C-M-E If in ErrList Mode, jumps to position of next compiler error and prints the error in the echo area. *note Error: Compile C-M-C Same Capitalization, make all occurences of word same cap. C-M-S No Comment Search, search for something ignoring comment contents. C-M-+ Turns previous variable name into command to increment that variable. That is, FOO C-M-+ turns into FOO:= FOO + 1; C-M-' Inserts a string of specified length and lets you recursively edit the contents of the string in overwrite mode. C-M-{ Pulls non-comment text from previous line beginning at character (asked for) and puts it on this line. Also performs indentation on the result. Useful when you want to change the way a line is broken. Pascal Mode Restart Pascal Mode Pascal Expand Abbrevs in Region Expands all abbrevs in region, but not in comments.  Node: Compile, Previous: Available, Next: Variables, Up: Top With the command M-X Compile (C-M-,) you can automatically compile and execute your program in an inferior exec. To get special compiler switches or to load other files with yours, put the switches and other files in the variable Compiler Switches. If you are in ErrList Mode, the compiler errors you see when you do M-X Compile (C-M-,) are saved away in the buffer named *LST*. You can jump to the position of the "next" error in your source file with the command C-M-E. Do this till the message "(No more errors)" appears. To go into ErrList Mode, just give the command M-X ErrList Mode. To get out, give the same command again. You can also get in by setting the variable, ErrList Mode, to something other than zero. This will work from an init or evars file (*Note: Init: (EMACS)INIT.) or a local modes list (*Note: Locals: (EMACS)Locals). You do not want to be in ErrList mode when you are not finding compiler errors because it is inefficient and it will be creating a .LST file every time you compile. Appologies: (1) In the current implementation this command creates a compiler listing of your program, which could waste a lot of space. If this is a problem, connect to a scratch directory while doing the compilation. It is also a good idea to have your source program on the same directory you are connected to. (2) The routine for jumping to the position of an error does not adjust for changes you have made to your file after the compilation. This means that it may show errors you have already fixed, and that the position it jumps to will be wrong if (a) you change the number of pages before the page with the error, or (b) you change the number of lines before the line with the error on the page with the error, or (c) you change the number of characters before position of the error on the line with the error.  Node: Variables, Previous: Available, Up: Top, Next: Indent The PASCAL library has several switches you can set to customize its behavior. For info on how to set variables *note Vars: (EMACS)Variables. Variable name D Explaination ---------------------------------------------------------------------------- ErrList Mode 0 If non-zero, compiler errors found with M-X Compile (C-M-,) are saved so that you can step through them with C-M-E. Indent Align Only 0 If non-zero, LINEFEED only aligns with previous line (does ^R Indent Nested). Indent After --- 4 For any keyword, Indent After is the amount to indent extra after seeing . Begin-Block Body Indentation 4 Default indent after BEGIN, REPEAT, CASE, LOOP, RECORD. IF-Block Body Indentation 4 Default indent after IF, THEN, ELSE, WHILE, FOR, DO, WITH. Decl Body Indentation 4 Default indent after CONST, TYPE, VAR, LABEL. --- Body Indentation 4 Amount to indent Body, but not variables, of subprogram keyword specified. Indentation for declaration section is Indent After --- PROCEDURE Body Indentation 4 Default for both "--- Body Indentation" and "Indent After ---" for PROCEDURE, FUNCTION, and PROGRAM. Indent After Everything 4 Default for any value not specified. Reindent ENDs 1 0 = leave ENDs & UNTILs indented same as statements in block; 1 = align END's with corresponding BEGIN line. Match Block Word 0 If non-zero, indentation after line with the keyword BEGIN, REPEAT, CASE, and RECORD will start from the position of the keyword within the line, not the indentation of the line. BEGIN on same line 0 Non-zero means inserted BEGINs are left on same line as stmt. THEN on same line 1 Non-zero means leave THEN on line with IF. ELSE on same line 0 Non-zero means try to stick ELSE on end of previous line. Automatic Capitalization: 0 If non-zero, all keywords typed or inserted are capitalized. Insert Comments 1 Non-zero means insert functions insert some labeling comments. -------------------Comment Controlling Variables-------------------- Comment Column 0 Where EMACS tries to start your comments (here or after your code). Global Comment Column 10 Comment Column when doing a Global Pascal Comment. Pascal Star Line Width 51 Do Describe on ^R Global Pascal Comment. Comment Rounding "+1" Algorithm which EMACS uses to figure where to start the comment if your code extends beyond the comment column. * Menu: * Examples:: Variable settings for various kinds of indentation.  File: EPASC, Node: Indent, Up: Top, Previous: Variables, Next: Statements PASCAL mode allows easy formatting of Pascal code as you type it in. Its main concern is with indentation, not with breaking lines, so that it fits in well with most styles of formatting. There is also a great deal of customization avaialable to suit individual tastes. Note: If the load is too high to effectively use the indentation package, or you just don't get along with it, you can turn it off by setting Indent Align Only to 1. This will force the indentation to only align with the previous line, without trying to figure out how much less or more to indent. * Menu: * Basics:: The basics of using PASCAL mode indentation * Details:: Some details about how indentation mode operates * Examples:: Variable settings for various kinds of indentation.  Node: Basics, Previous: Indent, Up: Indent, Next: Details The two indentation commands are LINEFEED and C-M-I. C-M-I calls the main routine to do indenting, and LINEFEED does a return, then calls C-M-I. While you are typing in a program, the normal mode of operation will be to type in your lines of code, and at the end of each line type LINEFEED instead of Return. This will cause EMACS to decide how far in the next statement should be indented. You can get the same effect by typing Return then C-M-I. C-M-I can also be used to indent or re-indent existing lines. If you type C-M-I at the beginning of an existing line, the line will be indented the way that EMACS thinks it ought to be. Typing C-M-I in the middle of a line will cause the rest of the line to be lined up with a word in the line above (i.e. M-X ^R Pascal Indent Relative is called). A special case is when you type LINEFEED after an END or UNTIL, or type C-M-I at the beginning of the line after an END or UNTIL. Doing either of these causes EMACS to go back and decide which BEGIN or REPEAT or other keyword the END (UNTIL) matches. It then will go and move the END (UNTIL) so that it lines up with the BEGIN or whatever. This allows you to not have to worry about trying to convince it that the line you are about to type is an END, not just another statement. Just type the END, which will be in the wrong place, then type LINEFEED, like you would with any line. It will go back and move the END so that it's in the right place. You can turn off this "feature" by setting the variable Reindent ENDs to zero. Note that, even though TABs are used for indentation, RUBOUT is redefined so that TABs act like 8 spaces. So, if you try to rub out a TAB, what you will get as a result is that you've moved one character position to the left on the screen. If you want to get the ordinary Rubout, you can use C-Rubout, which you can get by typing Control-^ followed by Rubout. Using LINEFEED and C-M-I, you should be able to do all of the formatting that you want. In cases where it fails, complain!  Node: Details, Previous: Basics, Up: Indent, Next: Statements If you know that EMACS is about to give you indentation that you don't want (see *note Failure: Future Work, for some known cases) you can be more specific about the indentation you want. Giving an argument to LINEFEED (or C-M-I) makes it run ^R Indent Nested. Positive arguments make it line up with a line levels out (to the left) of the previous line and negative arguments make in indent -arg spaces further in (to the right). This also works if you've set Indent Align Only. If there is no argument then if the cursor is not at the left margin, the indenter calls M-X ^R Pascal Indent Relative, which lines up with successive keywords on the previous line. Otherwise, if there is an un-matched open parenthesis or open comment in the previous 10 lines, it matches that. Otherwise it calls the indenter. If there is a keyword on the previous line and the line doesn't end with ";", the new line is indented to the amount of the previous line plus the amount specified by "Indent After " for the last keyword on the previous line. If no keyword is found or the line ends with a sem, we just line up with the previous statement, which may not be the previous line if it is a nested statement or the END of a compound statement. If the PREVIOUS line contains an END, it will be re-indented to match the matching BEGIN, unless Reindent END is zero. If the indentation you just got seems strange to you, you can get a short description of what was done (including a pointer to the point which was matched to get the base indentation) with M-X Print Last Pascal Indenter (C-M-?). To make the indenter ignore a keyword which it now recognizes, set the variable "Indent After " to -1. A description of the algorithm used is in *note Internal: Indentation.  Node: Statements, Previous: Indent, Up: Top, Next: Comments These are the available insertion commands: C-M-. E ^R Pascal END C-M-. W ^R Pascal WHILE C-M-. F ^R Pascal FOR C-M-.  ^R Pascal WITH C-M-. I ^R Pascal IF C-M-.  ^R Pascal ELSE C-M-. P ^R Pascal PROCEDURE C-M-.  ^R Pascal FUNCTION C-M-.  ^R Pascal PROGRAM C-M-. R ^R Pascal REPEAT C-M-. B ^R Pascal BEGIN C-M-. C ^R Pascal CASE C-M-.  ^R Pascal RECORD C-M-. B ^R Pascal BEGIN M-X ^R Pascal End goes back to an open block statement and inserts the corresponding close block (END or UNTIL). Use Describe (see *Note Help: (EMACS)Help.) on ^R Pascal End for more details. The general purpose of the other commands is to insert the redundant text in their kinds of statements. For some individualities of the commands, you can see their internal documentation via the Describe command. Here are some of their general properties: The column indented to is the current horizontal position or the indentation of the current line, if there is text on the line. For instance, if the cursor is at column three and C-M-F is pressed, this is inserted: FOR DO BEGIN END; (* FOR *) (assuming Indent After BEGIN = 3, Indent After DO = 3, and Capitalize Pascal Keywords = 1) but if the cursor is at the end of this line: while true do and C-M-B is pressed, this results: while true do begin end; (* while *) (if Capitalize Pascal Keywords = 0, Indent After BEGIN = 4, Match Block Word = 0). If given a positive argument, the macros will not insert the BEGIN/END pair (where this makes sense), except the PROCEDURE/FUNCTION/ PROGRAM group will not insert the line with VAR. If given a negative argument, they will try to enclose - lines within the BEGIN/END (or whatever) pair. If you want to enclose the region instead, do ^R Count Line Region (M-=) to see what argument to give. ^R Pascal Procedure and ^R Pascal Function will ask you for the subprogram name and parameters before it inserts the rest of the block. Type them normally into the buffer where the cursor is left and exit with C-M-C (C-M-Z on Twenex). Undoing and fixing: Any of the calls to these functions can be be taken back with M-X Undo$. Remember, they insert a lot of comments; if you don't want them, they can be killed individually with C-M-;. Setting Insert Comments to zero will stop them all from being inserted. * Menu: * Examples:: Variable settings for various kinds of indentation.  Node: Examples, Previous: Statements, Up: Top, Next: Statements EXAMPLE1 Variable settings. Procedure Body Indentation: 2 Indent After Procedure: 5 Indent after IF: 2 Indent after THEN: 2 Indent after ELSE: 1 Indent after BEGIN: 3 Indent after REPEAT: 4 Indent after DO: 3 Automatic Capitalization: 0 BEGIN on same line: 0 THEN on same line: 0 ELSE on same line: 0 Indentation (assuming start column is left margin). procedure xx; var b: integer; begin (* xx *) March; end; (* xx *) while Foo do begin Bar; end; (* while *) repeat Fosit; until false; if x then Bar else Rag; EXAMPLE2: The modern indentation style proposed by Arthur Sale might have these settings: Indent After Everything: 4 Automatic Capitalization: 1 BEGIN on same line: 1 THEN on same line: 1 ELSE on same line: 1 Match Block Word: 0 With resulting code indented this way: IF cond THEN BEGIN stmts; END; (* IF *) PROCEDURE Foo(bar,baz: real); VAR i: INTEGER; BEGIN (* Foo *) body; END; (* Foo *)  Node: Comments, Previous: Statements, Up: Top, Next: Paren Groups There are various things that you can do with comments in Pascal mode (most also work in other language mode). You can ask EMACS to start comments for you, go to the next comment, and go to the previous comment. There is also a global comment mode (only in Pascal) which allows you to enter a large comment, for instance at the beginning of a program. To ask EMACS to start a comment on the current line, use the command Meta-;. This will go to the end of the line and start a comment by inserting open and close comment brackets and leaving the point between them. If there is already a comment on the line, EMACS will realign it and then move into it. C-U C-X ; will create a comment lined up with comment on the previous line, and make all subsequent comments also try to start in that column. M-* will create a comment at the current cursor position always (Pascal only). If you want EMACS to always start comments no further left than a specific column, go to the column you want, and type C-X ; (Control-X Semicolon). EMACS should confirm by typing Comment Column = n at the bottom of the screen, where n is the column you changed it to. If you want to have the same one set up for you each time you start Pascal mode, set the variable Comment Column in you Pascal Mode Hook. *Note Vars: (EMACS)Variables. If you want to go on and enter a comment at the end of the next line, you can use the command M-N to move down to (and maybe create) a comment on the next line. Similarly, you can use M-P to go up a line and start a comment. To kill a comment at the end of the line use C-M-;. You can also use this to move a comment by killing it and then un-killing it where you want it to be. *Note Un-Killing: (EMACS)Un-killing. There is another way to enter comments, and that is the global comment mode. To use this, use the command M-X Global Pascal Comment. This will enter a special mode where you will be entering a block of comments. Each comment will start in the 2nd column, and will start with "(**" (or "{*"). You can use the commands M-;, M-N, and M-P as described above. When you're done entering the block of comments, exit the inner mode with C-M-C (C-M-Z on Twenex). As it leaves, it will convert the beginnings of the comments to "(* " (or "{ ", and move the ends so that they all line up. As it leaves the global comment mode, it will also convert any line which looks like "(*** *)" into a line of stars and spaces: "(* * * ...*)".  Node: Paren Groups, Previous: Comments, Up: Top, Next: Hints The parenthesis manipulation functions are really LISP commands and their names reflect it. A "Sexp" is (for our purposes) either a parenthesized expression or a single word (depending what we are next to). Commands for manipulating them are: C-M-F ^R Forward Sexp C-M-B ^R Backward Sexp C-M-K ^R Kill Sexp C-M-Rubout ^R Backward Kill Sexp C-M-K ^R Kill Sexp C-M-@ ^R Mark Sexp In addition to the Sexp's there are "Lists". These are also parenthesized expressions, but we have additional commands for moving "down" inside the parens and "up" out of the paren group. C-M-( ^R Backward Up List C-M-) ^R Forward Up List C-M-D ^R Down List C-M-U ^R Backward Up List  Node: Hints, Previous: Paren Groups, Up: Top, Next: Hackers . To figure out your BEGIN/END pairing, use the command M-X Display Matching Lines to show only the lines with a BEGIN or END. You can also use C-M-P and C-M-N to move over matching BEGIN/END (or REPEAT/UNTIL, etc.) pairs. . Use M-X ^R Indent Rigidly (C-X TAB) to conveniently change the indentation of a block of text. . Use ^R Back to Indentation (M-M) to move to the logical start of this line. ^R Up Indented Line and ^R Down Indented Line will move over their lines and end up at their logical start.  Node: Hackers, Previous: Hints, Up: Top, Next: Philosophy This section is designed for people intending to do work on Pascal Mode, to install it on another system, or to modify it into another language. It might also be interesting and/or helpful for a heavy user of Pascal Mode. * Menu: * Philosophy:: Reasons why some things are how they are. * Syntax Table:: Table which keeps the syntax of interesting keywords. * Install:: Information for somebody installing or re-targetting. * Algorithms:: Description of the less obvious algorithms used. * Future Work:: If you know or want to learn TECO and have time...  Node: Philosophy, Previous: Hackers, Up: Hackers, Next: Syntax Table The idea behind Pascal (or any language mode) in EMACS is to give the user extra support by allowing the editor to know something about the higher level structure of his file. At the same time, the reason there is not a seperate "structured editor" for Pascal is so that the basic commands will be common between all editing tasks. Because of the last point, it has been my attempt in Pascal Mode to minimize the disturbance of the user's basic editing. That's why I broke with standard EMACS philosophy and did not put the line indenter on TAB. The reasons all of the keys defined are control-meta- commands are 1) to provide a better mnemonic for the user to remember where all the Pascal commands are, 2) because they replace unused keys or dangerous LISP commands, and 3) so that there will be a consistent "language prefix" which users know will be squashed by the major modes. It is my opinion that more major modes should follow this practice. A lot of work has gone in to making the indentation commands correct and fast. This allows the user to ignore the question of indentation when typing in text and frees his concentration for more important aspects of the program. At the same time, I have attempted to keep the base algorithm as simple as possible; the user has to understand what is going on in the algorithm to get the most good out of it, and simple is better for that.  Node: Syntax Table, Previous: Philosophy, Up: Hackers, Next: Install The syntax table is read from EMACS:PASCAL.SYN by the function M-X & Read Keywords when Pascal is loaded. There is one line per keyword. The first word on the line is the keyword itself, the second word is the default indentation, and the third word is a binary word of the "descriptor" bits. On loading the Pascal library, the file is read into the q-vector variable Pascal Syntax Table. This variable exactly mirrors the structure of the file. The bits in the status word are decoded as follows: 1 (the least significant) is set for keywords which are "block beginners", things like BEGIN, REPEAT, RECORD & CASE; 2 is set for the "block enders"; 3 & 4 are set for ELSE and THEN, resp., because these are matched up with each other when going back over a nested statement; 5 is for non-compounding and non-if keywords like WHILE, DO, WITH; 6 is for the subprogram statements, PROGRAM, PROCEDURE & FUNCTION; 7 is for the declaration keywords, LABEL, TYPE, CONST, & VAR; 8 is for the IF-Block Body keywords (IF, THEN, ELSE); 9 is for THEN and DO because when they end a sub-statement, the following statement is nested from that statement; and 10 is for BEGIN alone becuase it has significance as a simple blocker the other "block beginners" don't have.  Node: Install, Previous: Syntax Table, Up: Hackers, Next: Algorithms Most of the language dependancies for indentation are keyed through the syntax table. If you can't get the indenter to work for your site by making changes to the syntax table, try adding a new entry to the syntax table and updating the indent macro for both languages. It will be nice to have as much in common as possible between structured languages. Any characters which can appear in keywords should be listed in the routines & Back To Word and & Forward To Word. Macros which would probably have to be replaced are Pascal Mode and & Default Init Pascal Mode. Macros which will have to be modified or replaced because of language dependancies which are not in the syntax table are the insert macros, Mark Procedure, and & Save Errors (which goes through the listing file getting the info on all the compiler errors when ErrList mode is in effect). There is also a shameful but necessary direct dependance on the syntax of the compiler. See & In ErrList Mode and the file PASCAL.MIC for places to make changes. Also, in general when I look to ignore comments or strings I assume that both "{}" and "(* *)" are comment delimiters in addition to the variables Comment Start and Comment End. This is becuase our version of Pascal allows both those comment delimiters and more. The routines where this occurs are M-X & Forward To Chars, M-X & Back To Chars, and M-X ^R Pascal Begin. In the former two routines I pass over quoted strings, which I assume are bounded by a single quote, "'", on each side. If your language uses different or alternate string delimiters this will have to be changed in line, too.  Node: Algorithms, Previous: Install, Up: Hackers, Next: Future Work Most of the algorithms used in the file are straight forward and are commented in line. * Menu: * Indentation:: How & Indent Line works * Error Saving:: Kluges for ErrList mode  Node: Indentation, Previous: Algorithms, Up: Algorithms, Next: Error Saving The indent macro has four phases it goes through in trying to indent a line: scanning for the key token, moving back over begin/end pairs, moving back to controlling statements if the one found is nested, and rejoining split lines. The first involves scaning back in the immediately previous line (or to any line which has an open paren or open comment for a close on this line) till it finds a keyword with a non-negative indent value or a block ender. If a semicolon is encountered it's presence is noted by setting the indent value to -2 (it starts as -1); after we see a sem we usually don't care if there is a keyword with a non-negative indent value (we want to line up with "IF x < 0 THEN Write(x);"). However, we do pick up an indent value if we see one of the subprogram keywords or declaration keywords (you want to indent extra after "VAR i: Integer;"). At the end of that stage, if we have found a positive indent keyword, we are at our goal; we will indent from this statement offset by the value of the indent for that keyword and skip the next two stages. If we found a Block Beginner and Match Block Word is set, allign with the word (and goto DONE0 to avoid calculating a new position). Otherwise align with the indentation of this statement (DONE1). Otherwise, we just want to line up with the proper line, but finding it will be tricky. In the next stage we continue back over the last line (and those connected by parens) to see if there is a block ender. If so, we use Back Level to move backwards to the matching beginer; the statement controling the one with the beginner keyword is the one we want to line up the next statement with. This section also takes care of re-indenting ENDs. There are two philosophies on aligning ENDs which are supported. One says they should be lined up with the statements of the block. To get this behavior the user sets Reindent End to zero -- END's will be left alone where the normal statement indenter put them. The philosophy holds that the END (or UNTIL) should match the indentation of either the line with the beginner or (if Match Block Word is set) the beginner word itself. In this case the END will not be indented correctly in the text because we indented it for a statement; this stage takes care of properly re-aligning it. The next stage goes back over nested statements (all substatements which end in THEN or DO nest the next statement) and THEN/ELSE pairs to the actual line we want to indent from. If we come to a THEN and the there was no SEM on the first line saw in the back parsing, assume the user is about to type an ELSE and indent the line the same as the THEN. When we finally have the exact statement we want to match, we still can't count on it's being entirely on the line we went to. When conditions for an IF or WHILE or such get too large people often split them between several lines. The simple fix is to scan back to the matching IF or WHILE or such whenever we wound up on a DO or THEN. The two complications are 1) we want to do the same thing for THEN BEGIN and 2) many people like to have the THEN on a seperate line from the IF. To fix (1) we just move back over a BEGIN before checking for the THEN/ELSE and to fix (2), we check to be sure that the THEN or DO is not the first word on the line. Now we finally have a line and a position in a line. The indentation is done and properly marked to be shown if the user is curious about what happened.  Node: Error Saving, Previous: Indentation, Up: Algorithms, Next: Algorithms None of the algorithms for this part are particularly brilliant; instead the problem is that they are somewhat klugy. There has been a constant race with the compiler developers who like to change the syntax for calling the compiler with a listing file and to change the format of the listing file itself. When ErrList mode is selected, the hooks used by M-X Compile are arranged so that a listing file will be created on the compilation and so that M-X & Compile Compilation will be called after the compile. M-X & Compile Compilation grabs the listing file in the buffer *LST* and deletes the file from disk. Then it calls M-X & Save Errors to extract the relevant information the errors from the listing file and build a q-vector to contain them. To find each error we search for a consistent string which the compiler puts on error lines. From the error line we get the error message (to display) and the position in the line of the error. From the previous line we extract the line number. While we are searching for the error messages we also keep the current page active. M-X ^R Next Error just keeps an index into the q-vector of error information. Each time it is called it updates the pointer, hops to page, line, and line pos of the error and prints out the error message. This will all work much better when I 1) hack the compiler to put out an error listing which contains just the errors and has the information I need in a more direct format (I might even convince it to give me the character position of the errors) and 2) hack TECO to have updating marks in the file. As things stand now, if the user inserts a page before the page of the error, or a line before the line of the error in the page of the error, or a character before the position of the error in the line of the error, everything is messed up. All those operations are reasonably likely in the course of fixing the previous errors. The fix will be to mark the positions of all the errors with updating marks so that we can still find them after all the changes have taken place.  Node: Future Work, Previous: Algorithms, Up: Hackers, Next: Hackers 1. Cases the indenter gets wrong A: After the declarations and before the BEGIN of a block we indent for another declaration. Fix: Re-indent previous line when BEGIN typed if previous keyword is a declaration keyword or subprogram keyword? Bad. B: After the last END of a procedure. Tends to line up with a declaration statement of the ENDed procedure instead of with the PROCEDURE line itself. Fix: ? C: Labels are totally ignored. I could find no clean way to handle them. Fix: Correct behavior = ? Statement labels (those which start on the left margin?) should be totally ignored, both in syntactic processing (make "back to token" ignore them?) and in determining the indentation of the line they're on. Case labels should probably have an indent after them if there is no text after them, but they should be ignored if there is text on the same line as them. D: After a THEN when it is on the same line as the IF. 2. Mark Procedure should be able to handle procedures with nested procedures. 3. Automatic capitalization should not expand the words in comments. This is easy but expensive to do. You just put a macro on each expansion definition which does a search backwards for an open or close comment. If an open comment is found, we are in an abbrev and the abbrev should be unexpanded. 4. Match Block Word should be replaced by a bit per keyword saying whether to match that keyword. This is for two reasons: 1) many people like to match RECORD but few like to match BEGIN and 2) this will allow people to indent like this if they want: IF c1 THEN WHILE c2 DO s; 5. The insert commands should be hacked to be one command parsing a general schema string. Maybe add a bit to the symbol table corresponding to "Indent After " to help out. 6. The language dependancies of Mark Procedure and the insert routines should be eliminated. The insert routines should have one driver to which a schema is passed; they are too ad hoc and messy as it is.