1 package edu.uci.eecs.codeGenerator;
3 import java.io.BufferedReader;
5 import java.io.FileNotFoundException;
6 import java.io.FileReader;
7 import java.io.IOException;
8 import java.io.LineNumberReader;
9 import java.util.ArrayList;
10 import java.util.Collections;
11 import java.util.HashMap;
13 import edu.uci.eecs.codeGenerator.CodeAdditions.CodeAddition;
14 import edu.uci.eecs.specExtraction.Code;
15 import edu.uci.eecs.specExtraction.Construct;
16 import edu.uci.eecs.specExtraction.DefineConstruct;
17 import edu.uci.eecs.specExtraction.EntryConstruct;
18 import edu.uci.eecs.specExtraction.InterfaceConstruct;
19 import edu.uci.eecs.specExtraction.OPConstruct;
20 import edu.uci.eecs.specExtraction.SpecExtractor;
21 import edu.uci.eecs.specExtraction.SpecNaming;
22 import edu.uci.eecs.specExtraction.WrongAnnotationException;
23 import edu.uci.eecs.utilParser.ParseException;
27 * This class represents the engine to generate instrumented code. To construct
28 * an object of this file, users need provide a string that represents the
29 * sub-directory under the benchmarks directory, then the engine will explore
30 * all the C/C++ files that ends with ".cc/.cpp/.c/.h" and extract specification
31 * annotations and generate instrumented code in the generated directory.
37 public class CodeGenerator {
38 // Files that we need to process
39 private ArrayList<File> files;
41 // Code addition list --- per file
42 private ArrayList<CodeAdditions> allAdditions;
43 // Line change map list --- per file; Each map represents the
44 // line->InterfaceConstruct mapping that will rename the interface
46 private ArrayList<HashMap<Integer, InterfaceConstruct>> renamedLinesMapList;
48 // The string that users provide as a sub-directory in the benchmarks
49 // directory: e.g. ms-queue
50 public final String dirName;
52 // The original directory --- the benchmarks directory: e.g.
53 // ~/model-checker/benchmarks/
54 public final String originalDir;
55 // The directory for generated files: e.g. ~/model-checker/test-cdsspec/
56 public final String generatedDir;
58 // The specification annotation extractor
59 private SpecExtractor extractor;
61 public CodeGenerator(String originalDir, String generatedDir, String dirName) {
62 this.dirName = dirName;
63 this.originalDir = originalDir + "/" + dirName + "/";
64 this.generatedDir = generatedDir + "/" + dirName + "/";
66 //this.originalDir = Environment.BenchmarksDir + dirName + "/";
67 //this.generatedDir = Environment.GeneratedFilesDir + dirName + "/";
70 files = this.getSrcFiles(this.originalDir);
71 System.out.println("Original benchmarks directory: " + this.originalDir);
72 System.out.println("Generated benchmark directory: " + this.generatedDir);
73 System.out.println("The specific benchmark directory: " + this.dirName);
74 for (int i = 0; i < files.size(); i++) {
75 System.out.println(" Processing: " + files.get(i));
77 } catch (FileNotFoundException e) {
80 extractor = new SpecExtractor();
82 extractor.extract(files);
83 } catch (WrongAnnotationException e) {
85 } catch (ParseException e) {
92 * This function initializes the list of code additions and line changes for
93 * all the files. For the code additions of a file, we sort them in an
94 * increasing order by the inserting line number.
98 private void getAllCodeChanges() {
99 allAdditions = new ArrayList<CodeAdditions>();
100 renamedLinesMapList = new ArrayList<HashMap<Integer, InterfaceConstruct>>();
101 for (int i = 0; i < files.size(); i++) {
102 File file = files.get(i);
103 // One CodeAdditions per file
104 CodeAdditions additions = new CodeAdditions(file);
105 // Add the additions for this file to the list
106 allAdditions.add(additions);
108 // One CodeChange per file
109 HashMap<Integer, InterfaceConstruct> renamedLinesMap = new HashMap<Integer, InterfaceConstruct>();
110 // Add it the the list
111 renamedLinesMapList.add(renamedLinesMap);
113 // Extract all the additions
114 ArrayList<OPConstruct> OPList = extractor.OPListMap.get(file);
115 EntryConstruct entry = extractor.entryMap.get(file);
116 ArrayList<DefineConstruct> defineList = extractor.defineListMap
118 ArrayList<InterfaceConstruct> interfaceList = extractor.interfaceListMap
121 CodeAddition addition = null;
122 // For ordering point constructs
123 if (OPList != null) {
124 for (OPConstruct con : OPList) {
125 code = CodeGeneratorUtils.Generate4OPConstruct(con);
126 addition = new CodeAddition(con.beginLineNum, code);
127 additions.addCodeAddition(addition);
130 // For entry constructs
132 code = CodeGeneratorUtils.Generate4Entry(entry);
133 addition = new CodeAddition(entry.beginLineNum, code);
134 additions.addCodeAddition(addition);
136 // For define constructs
137 if (defineList != null) {
138 for (DefineConstruct con : defineList) {
139 code = CodeGeneratorUtils.Generate4Define(con);
140 addition = new CodeAddition(con.endLineNum, code);
141 additions.addCodeAddition(addition);
144 // For interface constructs
145 if (interfaceList != null) {
146 for (InterfaceConstruct con : interfaceList) {
147 code = CodeGeneratorUtils.GenerateInterfaceWrapper(con);
148 addition = new CodeAddition(con.getEndLineNumFunction(),
150 additions.addCodeAddition(addition);
151 // Record the line to be changed
152 renamedLinesMap.put(con.endLineNum + 1, con);
156 // Sort additions by line number increasingly
163 * For a specific file, given the code additions and line changes mapping
164 * for that file, this function will generate the new code for that file and
165 * write it back to the destination directory.
169 * The file to be processed
171 * The sorted code additions for the file
172 * @param renamedLinesMap
173 * The line change mapping for the file
175 private void writeCodeChange(File file, CodeAdditions additions,
176 HashMap<Integer, InterfaceConstruct> renamedLinesMap) {
177 Code newCode = new Code();
178 BufferedReader br = null;
179 LineNumberReader lineReader = null;
181 String curLine = null;
183 String dest = generatedDir + file.getName();
184 CodeAddition curAddition = null;
185 int additionIdx = -1;
186 if (!additions.isEmpty()) {
188 curAddition = additions.codeAdditions.get(0);
191 // Include the header for C/C++ files (.c/.cc/.cpp)
192 String name = file.getName();
193 if (name.endsWith(".c") || name.endsWith(".cc")
194 || name.endsWith(".cpp")) {
195 newCode.addLine(CodeGeneratorUtils.Comment("Add the"
196 + SpecNaming.CDSSpecGeneratedHeader + " header file"));
197 newCode.addLine(CodeGeneratorUtils
198 .IncludeHeader(SpecNaming.CDSSpecGeneratedHeader));
203 br = new BufferedReader(new FileReader(file));
204 lineReader = new LineNumberReader(br);
205 while ((curLine = lineReader.readLine()) != null) {
206 lineNum = lineReader.getLineNumber();
207 InterfaceConstruct construct = null;
208 if ((construct = renamedLinesMap.get(lineNum)) != null) {
210 String newLine = construct.getFunctionHeader()
211 .getRenamedFuncLine();
212 newCode.addLine(newLine);
214 // First add the current line
215 newCode.addLine(curLine);
216 // Then check if we need to add code
217 if (curAddition != null
218 && lineNum == curAddition.insertingLine) {
219 // Need to insert code
220 newCode.addLines(curAddition.code);
221 // Increase to the next code addition
223 curAddition = additionIdx == additions.codeAdditions
224 .size() ? null : additions.codeAdditions
229 // Write new code change to destination
230 CodeGeneratorUtils.write2File(dest, newCode.lines);
231 // System.out.println("/*************** " + file.getName()
232 // + " *************/");
233 // System.out.println(newCode);
234 } catch (FileNotFoundException e) {
236 } catch (IOException e) {
243 * This function is the main interface for the CodeGenerator class. After
244 * constructing a CodeGenerator object, users can call this function to
245 * complete the code generation and file writing process.
248 public void generateCode() {
249 // Extract all the code additions and line change
252 // Generate the header file and CPP file
253 Code generatedHeader = CodeGeneratorUtils
254 .GenerateCDSSpecHeaderFile(extractor);
255 Code generatedCPP = CodeGeneratorUtils
256 .GenerateCDSSpecCPPFile(extractor);
258 .write2File(generatedDir + SpecNaming.CDSSpecGeneratedName
259 + ".h", generatedHeader.lines);
260 CodeGeneratorUtils.write2File(generatedDir
261 + SpecNaming.CDSSpecGeneratedCPP, generatedCPP.lines);
263 // Iterate over each file
264 for (int i = 0; i < files.size(); i++) {
265 File file = files.get(i);
266 CodeAdditions additions = allAdditions.get(i);
267 HashMap<Integer, InterfaceConstruct> renamedLinesMap = renamedLinesMapList
269 writeCodeChange(file, additions, renamedLinesMap);
275 * This is just a testing function that outputs the generated code, but not
276 * actually write them to the disk.
279 private void testGenerator() {
280 // Test code generation
281 Code generatedHeader = CodeGeneratorUtils
282 .GenerateCDSSpecHeaderFile(extractor);
283 Code generatedCPP = CodeGeneratorUtils
284 .GenerateCDSSpecCPPFile(extractor);
286 System.out.println("/***** Generated header file *****/");
287 System.out.println(generatedHeader);
288 System.out.println("/***** Generated cpp file *****/");
289 System.out.println(generatedCPP);
291 for (File file : extractor.OPListMap.keySet()) {
292 ArrayList<OPConstruct> list = extractor.OPListMap.get(file);
293 for (OPConstruct con : list) {
294 Code code = CodeGeneratorUtils.Generate4OPConstruct(con);
295 System.out.println("/***** *****/");
296 System.out.println(con.annotation);
297 System.out.println(code);
301 for (File f : extractor.entryMap.keySet()) {
302 EntryConstruct con = extractor.entryMap.get(f);
303 System.out.println("/***** *****/");
304 System.out.println(con.annotation);
305 System.out.println(CodeGeneratorUtils.Generate4Entry(con));
308 for (File file : extractor.interfaceListMap.keySet()) {
309 ArrayList<InterfaceConstruct> list = extractor.interfaceListMap
311 for (InterfaceConstruct con : list) {
312 Code code = CodeGeneratorUtils.GenerateInterfaceWrapper(con);
313 System.out.println("/***** Interface wrapper *****/");
314 System.out.println(con.getFunctionHeader().getHeaderLine());
316 .println(con.getFunctionHeader().getRenamedFuncLine());
317 System.out.println(code);
322 public ArrayList<File> getSrcFiles(String dirName)
323 throws FileNotFoundException {
324 ArrayList<File> res = new ArrayList<File>();
325 File dir = new File(dirName);
326 if (dir.isDirectory() && dir.exists()) {
327 for (String file : dir.list()) {
328 if (file.endsWith(".h") || file.endsWith(".c")
329 || file.endsWith(".cc") || file.endsWith(".cpp")) {
330 res.add(new File(dir.getAbsolutePath() + "/" + file));
334 throw new FileNotFoundException(dirName
335 + " is not a valid directory!");
340 static public void main(String[] args) {
341 if (args.length < 3) {
343 .println("Usage: CodeGenerator <Benchmarks-directory> <Directory-for-generated-files> <specific-benchmark-lists...>");
347 // String[] dirNames = args;
349 // String[] dirNames = new String[args.length - 2];
350 // for (int i = 0; i < args.length - 2; i++) {
351 // dirNames[i] = args[i + 2];
353 String[] dirNames = Environment.Benchmarks;
355 for (int i = 0; i < dirNames.length; i++) {
356 String dirName = dirNames[i];
357 System.out.println("/********** Generating CDSSpec files for "
358 + dirName + " **********/");
359 // CodeGenerator generator = new CodeGenerator(Environment.BenchmarksDir, Environment.GeneratedFilesDir, dirName);
360 CodeGenerator generator = new CodeGenerator(args[0], args[1], dirName);
361 generator.generateCode();