62
CHAPTER 4
B
UILDING
SIMPLE
GENERATORS
4.1
T
HE
CODE
MUNGER
GENERATOR
TYPE
Code munging is the simplest of the code generation models and thus serves as the
starting point for our introduction to developing code generators. The code munger
takes executable code (e.g., C, Java, C++, SQL), parses the file, and produces some
useful output. In this section, we explain what a code munger does and show you six
different variants on this fundamental generator type. 
4.1.1
Uses and example code
Simple as they are, code mungers solve quite a few difficult problems. For instance, you
can use them to:
• Create documentation by reading special comments from a file and creating
HTML as output. (An example of this is a JavaDoc.)
• Catalog strings that will require internationalization.
• Report on resource identifier usage.
• Analyze code and report compliance with company standards. 
• Create indices of classes, methods, or functions. 
• Find and catalog global variable declarations. 
A code munger takes an input file, often source code, and searches it for patterns. Once
it finds those patterns, it creates a set of one or more output files, as figure 4.1 shows.
Now let’s take a look at some specific types of mungers.
Code munger 1—parsing C macros
Our first code munger reads C files looking for #define macros. A #define macro
in C looks like this:
#define MY_SYMBOL "a value"
For example:
#define PI 3.4159
The munger should find any #define macros and create an output file that contains
a line for each symbol, using this format: 
[symbol name],[symbol value]
SourceCode
CodeMunger
OutputFile
Figure 4.1
The input and output 
flow of a code munger
Pdf page size limit - Compress reduce PDF size in C#.net, ASP.NET, MVC, Ajax, WinForms, WPF
C# Code & .NET API to Compress & Decompress PDF Document
pdf font size change; pdf change font size
Pdf page size limit - VB.NET PDF File Compress Library: Compress reduce PDF size in vb.net, ASP.NET, MVC, Ajax, WinForms, WPF
VB.NET PDF Document Compression and Decompression Control SDK
reader pdf reduce file size; adjusting page size in pdf
T
HE
CODE
MUNGER
GENERATOR
TYPE
63
We’ll show four variants of the code. The first reads a single file; the second scans a
directory and reads all of the eligible files; the third reads the file contents from
standard input; and the fourth reads from a file but uses the language parser toolkit
to read the #define values. Figure 4.2 shows the first three variants in block
architecture form. 
The advantages of each approach are:
• Reading from a single file—This type of code munger is ideal for integration
within a Makefile or build process, since it works in the standard compiler style
of one input or one or more output files. This type of I/O flow works with the
external tool model as described in appendix D. 
• Reading from a directory—This approach is valuable because the code munger
can handle a growing repository of files without the need for code alterations. 
• Reading from standard input—If the munger reads from standard input, then it
can be embedded into IDEs. This type of I/O flow works with the filter model
described in appendix D. 
Here is our input file for the first variant, which reads from a single file:
#include <stdio.h>
#define HELLO "hello"
#define THERE "there"
int main( int argc, char *argv[] )
{
printf( "%s %s\n", HELLO, THERE );
return 0;
}
The two #define macros define HELLO and THERE. The output file should look
like this:
HELLO,"hello"
THERE,"there"
CM1
CodeMunger
OutputFile
CFile
CodeMunger
OutputFile
Directory
CodeMunger
OutputFile
StandardInput
CM1a
CM1b
Figure 4.2 2 The three basic code munger input models, 
which handle a file, a directory, and standard input
VB.NET PDF File Split Library: Split, seperate PDF into multiple
PDF document file to one-page PDF files or As String = Program.RootPath + "\\" 1.pdf" ' set split SplitOptions(SplitMode.BySize) ' limit the size of each
change font size pdf comment box; change font size pdf document
C# PDF File Split Library: Split, seperate PDF into multiple files
options = new SplitOptions(SplitMode.BySize); //limit the size of each String inputFilePath = Program.RootPath + "\\" source.pdf"; //Page indexes to
pdf compression; can a pdf file be compressed
64
CHAPTER 4
B
UILDING
SIMPLE
GENERATORS
The two symbols and their values are dumped into the file in comma-separated val-
ues (CSV) format. The Ruby generator to accomplish this is shown in listing 4.1. 
unless ARGV[0]                                             
print "cm1 usage: cm1 file.c\n"                          
exit                                                     
end                                                        
File.open( "out.txt", "w" ) { |out_fh|         
File.open( ARGV[0] ).each_line { |line|       
next unless ( line =~ /^#define\s+(.*?)\s+(.*?)$/ )    
out_fh.print "#{$1},#{$2}\n"   
}
}
q
This code checks to make sure that you have a value from the command line. If you
don’t, then it prints a friendly usage statement and exits the program.
w
The first call to File.open opens a new file for output. The first parameter is the
file-name and the second optional flag is the mode, in this case w (for writing). The
default mode is r (for reading). If the file can be opened for writing, then the code
block is executed and the file handle is passed to the block.
e
The second call to File.open opens the input file that was specified on the com-
mand line. This time, however, we use the each_line iterator to walk through the
file line by line. 
r
This regular expression serves two purposes. First, the expression checks to see if the
line is a #define macro. If it isn’t a #define macro, then the next operator is exe-
cuted and the regular expression goes on to the next line. The second function gets the
symbol and value text items from the #define macro if it finds one. The regular
expression is broken out in figure 4.3. The expression looks for a full line because the ^
and $ markers are specified. The line should start with #define followed by some
white space, followed directly by two segments delimited by white space.
Listing 4.1 1 Code munger 1, first variant: reading from a single file
Checks the command-line argument
q
Opens the output file
w
Reads a line from the input file
e
Looks for the 
#define macros
r
Prints to the 
output file
^#define\s+(.*?)\s+(.*?)$
Thebeginning
oftheline
Thetext'#define'
Oneormorewhitespacecharacters
Anytypeoftextgroupedtogetheras
$1
Anytypeoftextgroupedtogetheras
$2
Theend
oftheline
Figure 4.3
A breakout of the 
#define
macro 
regular expression
C# PowerPoint: How to Set PowerPoint Rendering Parameters in C#
2007 or above) slide into PDF document or other rendering process if the slide/page is too REImage CropImage(Rectangle sourceRegion, Size targetSize); Bitmap
pdf optimized format; best pdf compression tool
C# Excel: Customize Excel Conversion by Setting Rendering Options
0, (int)(originalWidth), (int)(originalHeight / 2)), new Size((int)(originalWidth the top half of Excel page to image to these file formats, like PDF, TIFF, SVG
change pdf page size; .pdf printing in thumbnail size
T
HE
CODE
MUNGER
GENERATOR
TYPE
65
It is a shame that regular expressions are often regarded as line noise. They are
extremely powerful once you get a knack for the syntax. An easy way to learn regular
expressions is to use your favorite editor to test regular expression search patterns
against the file you want to read. Although regular expression syntax is not consistent
across all applications and languages, there is usually a great deal of similarity, and it
should be easy to convert the regular expression you develop to the Ruby regular
expression syntax.
The second code munger variant reads a directory, finds any C files, and scans
them for macros. The code is shown in listing 4.2. 
unless ARGV[0]                            
print "cm1a usage: cm1a dir\n"
exit
end
File.open( "out.txt", "w" ) { |out_fh|
Dir.open( ARGV[0] ).each { |file|                            
next unless ( file =~ /[.]c$/ )                            
print "Reading #{file}\n"
File.open( file ).each_line { |line|
next unless ( line =~ /^#define\s+(.*?)\s+(.*?)$/ )
out_fh.print "#{$1},#{$2}\n"
}
}
}
q
This code checks to make sure that you have a value from the command line. If you
don’t, then it prints a friendly usage statement and exits the program.
w
The Ruby Dir class is a portable directory access class. The open method opens the
directory for reading. The each iterator then walks through every file in the directory
and sends the files into the code block one by one.
e
This code uses a simple regular expression to disqualify any files that do not end with
.c. This regular expression is broken out in figure 4.4. The period character in a regular
expression represents any character, so when you actually want to specify a period you
need to use the [.] syntax. The c string matches “c” and the $ means the end of the
line. The expression reads search for .c at the end of the string. When applied to a file-
name string, this means match any filename that has a .c extension.
Listing 4.2 2 Code munger 1, second variant: parsing a directory
Reads the directory
w
Ignores anything 
other than C files
e
Checks the command-
line arguments
q
[.]c$
Theendof
theline
The'.'
character
Thetext'c'
Figure 4.4
A breakout of the .c regular expression
VB.NET Excel: VB Methods to Set and Customize Excel Rendering
treat every single Excel spreadsheet as a page in our the fixed image size ration that the size is limited Excel to other document files, like PDF with online
pdf change font size in textbox; best way to compress pdf
66
CHAPTER 4
B
UILDING
SIMPLE
GENERATORS
The third variant (listing 4.3) uses the standard input for the contents of the C file
and then creates the out.txt file in response. 
File.open( "out.txt", "w" ) { |out_fh|
$stdin.each_line { |line|                                  
next unless ( line =~ /^#define\s+(.*?)\s+(.*?)$/ ) 
out_fh.print "#{$1},#{$2}\n"
}
}
q
The global $stdin stands for standard input. This object can be used as if it were any
file that was opened as read only.
The fourth variant (listing 4.4) reads from a file but uses the language parser toolkit to
get the macro names. 
require "CTokenizer"                                  
require "CLanguageScanner"                            
unless ARGV[0]
print "cm1c usage: cm1c file.c\n"
exit
end
File.open( "out.txt", "w" ) { |out_fh|
tokenizer = CTokenizer.new( )                       
tokenizer.parse( File.open( ARGV[0] ).read() )      
languagescanner = CLanguageScanner.new()            
languagescanner.parse( tokenizer.tokens )           
languagescanner.defines.each{ |key,value|           
out_fh.print "#{key},#{value}\n"                  
                                                  
}
Code munger 2—parsing C comments
The second example code munger looks for special comments in a C file. You’ll find
this example useful if you want to create a special markup language that can be used in
close proximity with the code. Here is our example input file:
// @important Something important
// @important Something very important
int main( int argc, char *argv[] )
{
Listing 4.3 3 Code munger 1, third variant: reading from standard input
Reads input 
from stdin
q
Listing 4.4 4 Code munger 1, fourth variant: reading from a file 
using the language parser toolkit
Imports the tokenizer 
and scanner
Scans for C language constructs
Builds the tokenizer 
and reads input
Outputs any 
#define values
T
HE
CODE
MUNGER
GENERATOR
TYPE
67
printf( "Hello World\n" );
return 0;
}
The special comment format is:
// @important ...
Everything after the // @important prefix is the content of the comment. You
can choose whatever terms you like for your comment tags by altering the regular
expression in the sample code.
This code munger’s job is to find the comments and then store the contents of the
comments in an output file. The output file should look like this:
Something important
Something very important
Listing 4.5 contains the Ruby code you use to implement this.
unless ARGV[0]                             
print "cm2 usage: cm2 file.c\n"
exit
end
File.open( "out.txt", "w" ) { |out_fh|
File.open( ARGV[0] ).each_line { |line|
next unless ( line =~ /^\/\/\s+@important\s+(.*?)$/ )  
out_fh.print "#{$1}\n"
}
}
q
This code checks to make sure that you have a value from the command line. If you
don’t, then it prints a friendly usage statement and exits the program.
w
The heart of this code is the regular expression, which is shown broken out in figure 4.5.
The caret symbol (^) at the beginning of the expression symbolizes the beginning of
the line. The next four characters—the ones that look like a steeplechase—are the two
forward slashes of the comment. Because the forward slash is a reserved character, it
needs to be escaped, which means putting a backslash before the character. This is how
you end up with the steeplechase pattern: \/\/.
After that, you want to look for one or more whitespace characters and then the
@important string. Following that is one or more whitespace characters. Then, use
the parentheses to gather together all of the text until the end of the line, which is spec-
ified by the $ character.
Listing 4.5 5 Code munger 2: Looks for specific comments in a C file
Checks the 
command line
q
Looks for 
comments
w
68
CHAPTER 4
B
UILDING
SIMPLE
GENERATORS
Code munger 3: pretty printing C as HTML
One very common use of a code munger is the wholesale conversion of the input file
into an entirely new format. Our next example does exactly this type of conversion: the
input is a C file and the output is HTML. A typical use for this type of converter
would be to generate code fragments for documentation or to create standalone pages
that are the end point of some code documentation.
Here is our example C file that we would like to turn into HTML:
// A test file for CM2
//
#include <stdio.h>
// @important Something important
// @important Something very important
int main( int argc, char *argv[] )
{
printf( "Hello World\n" );
return 0;
}
We don’t want anything too fancy in the HTML. The title should be the name of
the file, and the code should be displayed in Courier. In the next version, you can
consider doing some syntax coloring. Here is the type of HTML you should expect
from the generator:
<html>
<head>
<title>test.c</title>
</head>
<body>
<font face="Courier">
//&nbsp;A&nbsp;test&nbsp;file&nbsp;for&nbsp;cm2<br>
//<br>
#include&nbsp;&lt;stdio.h&gt;<br>
<br>
//&nbsp;@important&nbsp;Something&nbsp;important<br>
//&nbsp;@important&nbsp;Something&nbsp;very&nbsp;important<br>
^\/\/\s+@important\s+(.*?)$
Thebeginning
oftheline
Thetext'@important'
Oneormorewhitespacecharacters
Anytypeoftextgroupedtogetheras
$1
Theend
oftheline
Theleadingforwardslashes
Figure 4.5 5 A breakout of the 
@important
comment regular expression
T
HE
CODE
MUNGER
GENERATOR
TYPE
69
<br>
int&nbsp;main(&nbsp;int&nbsp;argc,&nbsp;char&nbsp;*argv[]&nbsp;)<br>
{<br>
&nbsp;&nbsp;&nbsp;printf(&nbsp;"Hello&nbsp;World\n"&nbsp;);<br>
&nbsp;&nbsp;&nbsp;return&nbsp;0;<br>
}<br>
</font>
</body>
</html>
Figure 4.6 shows the result when viewed in a web browser. 
The Ruby for our HTML-converting code munger is shown in listing 4.6.
unless ARGV[0]                            
print "cm3 usage: cm3 files ...\n"
exit
end
ARGV.each { |file|
text = File.open( file ).read()
text.gsub!( /\&/, "&amp;" )                   
text.gsub!( /\</, "&lt;" )                   
text.gsub!( /\>/, "&gt;" )                    
text.gsub!( / /, "&nbsp;" )                   
text.gsub!( /\t/, "&nbsp;&nbsp;&nbsp;" )      
text.gsub!( /\n/m, "<br>\n" )                 
html_file_name = "#{file}.html"
print "Creating #{html_file_name}\n"
File.open( html_file_name, "w" ) { |fh|
fh.print "<html>\n<head>\n"                      
fh.print "<title>#{file}</title>\n</head>\n"     
fh.print "<body>\n<font face=\"Courier\">\n"     
Figure 4.6
The HTML generated for 
test.c shown in a browser
Listing 4.6 6 Code munger 3: Converts a C file to HTML
Replaces end-of-
line characters
e
Contains the 
HTML header
r
Replaces 
white space
w
Replaces special 
characters with 
HTML entities
q
Checks the 
command line
70
CHAPTER 4
B
UILDING
SIMPLE
GENERATORS
fh.print text                            
fh.print "</font>\n</body>\n</html>\n"           
}
}
q
The first set of regular expression substitutions scans the complete text and turns spe-
cial characters into entity references. HTML uses &lt;&gt; and &amp; in place of
<>, and &.
w
The second section of regular expressions turns spaces and tabs into nonbreaking
spaces. We do this because HTML collapses white space on display. To preserve our for-
matting, we need to turn our spaces and tables into nonbreaking spaces, which are
specified using the &nbsp; entity.
e
The last regular expression turns the returns into 
<br>
tags with returns after them.
These <br> tags are line break symbols in HTML.
r
This is the HTML preamble that goes before the code text that we have converted into
HTML. The important thing to notice is the insertion of the filename using Ruby’s
#{expression} syntax.
t
This is the HTML post-amble that closes up the HTML output file.
Code munger 4: filtering XML
Another common use for a code munger is to filter the input file into a new output file.
These types of code mungers are usually built as a one-off to do some type of process-
ing on a file where the output is then used as the new master file. The original file and
the generator are then discarded. 
This code munger example takes some XML as input and adds some attributes to
it, and then creates a new output file with the adjusted XML. Here is our example
input file:
<classes>
<class name="foo">
<field>bar1</field>
<field>bar2</field>
</class>
</classes>
We want to add a type attribute to each field. To keep the example small, the type will
always be integer. The output file should look like this:
<classes>
<class name='foo'>
<field type='integer'>bar1</field>
<field type='integer'>bar2</field>
</class>
</classes>
Contains the HTML footer
t
Generates the HTML body
T
HE
CODE
MUNGER
GENERATOR
TYPE
71
One approach to transform between two XML schemas is to use Extensible Stylesheet
Language Transformations (XSLT). Another is to make a dedicated code munger that
acts as a filter. The code for the XML filter code munger appears in listing 4.7. 
require "rexml/document"
unless ARGV[0]
print "cm4 usage: cm4 files ...\n"
exit
end
doc = REXML::Document.new( File.open( ARGV[0] ).read )                
doc.root.each_element( "class/field" ) { |field|                      
field.attributes.add( REXML::Attribute.new( "type", "integer" ) )   
}
new_file_name = "#{ARGV[0]}.new"                                      
print "Creating #{new_file_name}\n"                                   
File.open( new_file_name, "w" ).write( doc.to_s )                     
q
Using REXML::Document.new we construct a new XML document object from
the contents of the input file. If this is successful, then all of the XML in the input file
will be in memory.
w
The each_element iterator finds all of the elements that match the given pattern
and then passes them into the code block. You should note that the code uses a hierar-
chical specification for the node by passing in the string "class/field". This tells
each_element that we want the field elements within the class elements.
e
Using the add method we add a new attribute object to the field. This attribute object
is created with a key and value pair where the key is type and the value is integer.
r
Rexml makes building an XML file easy. You create the file using the standard Ruby
File object, then use the to-string method (to_s) on the rexml root object to
create the text of the altered XML.
Code munger 5: generating C static data
from a CSV file
This munger uses the data stored in a CSV file to build a C implementation file
that contains all of the data in an array of structures. You could use this file in
building static lookup data for use during execution from the output of a database
or spreadsheet.
Here’s our example data file:
"Larry","Wall"
"Brian","Kerninghan"
"Dennis","Ritchie"
Listing 4.7 7 Code munger 4: Transforms an XML file
Reads the 
original XML
q
Creates the new file
r
Inspects each field
w
Adds the new
attribute
e
Documents you may be interested
Documents you may be interested