ttlogo.jpg Free TextTransformer Projects
Home
Text2HTML
Wikipedia
Yacc2TT
Delphi parser
Delphi preprocessor
Delphi pretty printer
Java parser
C preprocessor
C parser
HTML4
Utilities
MIME parser
Spamfilter
Additional Examples
Free components
  Minimal Website   Impressum

DelphiPrettyPrint

With the project DelphiPrettyPrint.ttp the readability of Delphi source code can be improved by formattingit in a uniform way so that the program structure is emphasized. E.g. the code:

procedure TTable .  InitFieldDefs;

begin
if(FHandle<>nil) then InternalInitFieldDefs else begin
    SetDBFlag(dbfFieldList,True);  end; end;

becomes to:

procedure TTable.InitFieldDefs;
begin
  if ( FHandle <> nil ) then
    InternalInitFieldDefs
  else
    begin
      SetDBFlag ( dbfFieldList, True );
    end;
end;

The code formatter is based on the Delphi parser Delphi.ttp and was made at first, as a demonstration of TextTransformer techniques to manipulate parse-trees, which are generated from the parser, to get a desired output format. However, the formatter absolutely also can be useful itself.


Original Pascal pretty-printer


The project was inspired by the Pascal pretty-printer:

http://www.moorecad.com/standardpascal/prettyp.pas

Some features of this origin still can be recognized in the present project. For the Delphi-pretty-printer, however, the token based approach of the Pascal formatter doesn't suffice. It is important in the far more complex Delphi to know at which place of the grammar a respective token is.


Processing the parse tree

The basic actions involved in prettyprinting are the indentation and de-indentation of the margin. Each time the margin is indented, the previous value of the margin is pushed onto a stack. Each time the margin is de-indented, the stack is popped off to obtain the previous value of the margin.

These and other actions are triggered when the parse-tree is passed top down. The actions are assigned to the labels of the nodes in the function table "m_ftTree". The indentations mostly are triggered by nodes, which represent special tokens, and the deindentations usually are triggered at the end of certain productions.


Actions of token representing nodes


Just like in the Pascal pretty-printer there is a table in DelphiPrettyPrint.ttp which assigns sets of options to certain tokens, which determine what happens when the token is written into the output.

The prettyprinting options are processed in the following order, and invoke the following actions:

CRSUPPRESS  - if a carriage return has been inserted following the previous symbol, then it is inhibited. 
CRBEFORE  - a carriage return is inserted before the current symbol (unless one is already there) 
BLANKLINEBEFORE  - a blank line is inserted before the current symbol (unless already there). 
DINDENT  - the stack is unconditionally popped and the margin is de-indented. 
SPACEBEFORESUPPRESS  - if a white space has been inserted following the previous symbol, then it is inhibited. 
SPACEBEFORE  - a space is inserted before the symbol being printed (unless already there). 

[ the symbol is printed at this point ]

SPACEAFTERSUPPRESS  - a white space following the symbol being printed is suppressed. 
INDENTBYTAB  - the margin is indented by a standard amount from the previous margin. 
INDENTTOCLP  - the margin is indented to the current line position. 
CRAFTER  - a carriage return is inserted following the symbol printed. 

The options are set as attributes of nodes and saved in the map "m_mPrettyPrint" in the initialization routine "InitPrettyPrint". In the action "Tree_keyword" they are forwarded as a context for the following actions.


Actions of production representing nodes

The deindentation usually cannot be assigned so easily to a token as in the case of the "compound_statement" which starts with "begin" and ends with "end". Therefore the PopIndent action is usually triggered at the end of certain productions. E.g. the action "Tree_deindent" is assigned to the "for_stmt" in which the token "do" triggers the indentation.

m_ftTree.add("for_stmt", Tree_deindent);

In the generated C++ code the function looks like:

void Csource_moduleParser::Tree_deindent(state_type& xState, 
                                         const node& xnNode, 
                                         str& xsResult, 
                                         node& xnContext)
{
  node n(Tree_Default( xState, xnNode, xsResult, xnContext ));
  PopIndent();
} 

I.e. at first the default action "Tree_Default" is executed, in which among others the action assigned to the "do" is triggered, and the PopIndent action which pops the indentation stack is executed afterwards.



Comments

Comments are stored in the map "m_Comments" as little trees and linked to the last tree node as an attribute when parsing. The comments are output essentially unchanged at the processing of the tree. To this there is a separate function table "m_ftCommentTree" for the treatment of the comment nodes. For line comments the ending line break is not saved. To prevent possible blank lines instead, as in the case of the CRAFTER option, a flag is set, that causes a single line break before outputting the next token.


Configuration

At the beginning of the start rule "source_module" character and degree for the indentation are set and can be changed easily by the user.

{{
SetIndenter(' ');
m_iIndent = 2;
}}



Last update: 12/31/09
1.1.6 local options of the comment productions corrected, such that no characters are ignored any more
1.1.5
1.0.8 contains much of the changes of Delphi.ttp 1.1.0

 to the top