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 dirName) {
62 this.dirName = dirName;
63 originalDir = Environment.BenchmarksDir + dirName + "/";
64 generatedDir = Environment.GeneratedFilesDir + dirName + "/";
66 files = this.getSrcFiles(originalDir);
67 } catch (FileNotFoundException e) {
70 extractor = new SpecExtractor();
72 extractor.extract(files);
73 } catch (WrongAnnotationException e) {
75 } catch (ParseException e) {
82 * This function initializes the list of code additions and line changes for
83 * all the files. For the code additions of a file, we sort them in an
84 * increasing order by the inserting line number.
88 private void getAllCodeChanges() {
89 allAdditions = new ArrayList<CodeAdditions>();
90 renamedLinesMapList = new ArrayList<HashMap<Integer, InterfaceConstruct>>();
91 for (int i = 0; i < files.size(); i++) {
92 File file = files.get(i);
93 // One CodeAdditions per file
94 CodeAdditions additions = new CodeAdditions(file);
95 // Add the additions for this file to the list
96 allAdditions.add(additions);
98 // One CodeChange per file
99 HashMap<Integer, InterfaceConstruct> renamedLinesMap = new HashMap<Integer, InterfaceConstruct>();
100 // Add it the the list
101 renamedLinesMapList.add(renamedLinesMap);
103 // Extract all the additions
104 ArrayList<OPConstruct> OPList = extractor.OPListMap.get(file);
105 EntryConstruct entry = extractor.entryMap.get(file);
106 ArrayList<DefineConstruct> defineList = extractor.defineListMap
108 ArrayList<InterfaceConstruct> interfaceList = extractor.interfaceListMap
111 CodeAddition addition = null;
112 // For ordering point constructs
113 if (OPList != null) {
114 for (OPConstruct con : OPList) {
115 code = CodeGeneratorUtils.Generate4OPConstruct(con);
116 addition = new CodeAddition(con.beginLineNum, code);
117 additions.addCodeAddition(addition);
120 // For entry constructs
122 code = CodeGeneratorUtils.Generate4Entry(entry);
123 addition = new CodeAddition(entry.beginLineNum, code);
124 additions.addCodeAddition(addition);
126 // For define constructs
127 if (defineList != null) {
128 for (DefineConstruct con : defineList) {
129 code = CodeGeneratorUtils.Generate4Define(con);
130 addition = new CodeAddition(con.endLineNum,
132 additions.addCodeAddition(addition);
135 // For interface constructs
136 if (interfaceList != null) {
137 for (InterfaceConstruct con : interfaceList) {
138 code = CodeGeneratorUtils.GenerateInterfaceWrapper(con);
139 addition = new CodeAddition(con.getEndLineNumFunction(),
141 additions.addCodeAddition(addition);
142 // Record the line to be changed
143 renamedLinesMap.put(con.endLineNum + 1, con);
147 // Sort additions by line number increasingly
154 * For a specific file, given the code additions and line changes mapping
155 * for that file, this function will generate the new code for that file and
156 * write it back to the destination directory.
160 * The file to be processed
162 * The sorted code additions for the file
163 * @param renamedLinesMap
164 * The line change mapping for the file
166 private void writeCodeChange(File file, CodeAdditions additions,
167 HashMap<Integer, InterfaceConstruct> renamedLinesMap) {
168 Code newCode = new Code();
169 BufferedReader br = null;
170 LineNumberReader lineReader = null;
172 String curLine = null;
174 String dest = generatedDir + file.getName();
175 CodeAddition curAddition = null;
176 int additionIdx = -1;
177 if (!additions.isEmpty()) {
179 curAddition = additions.codeAdditions.get(0);
182 // Include the header for C/C++ files (.c/.cc/.cpp)
183 String name = file.getName();
184 if (name.endsWith(".c") || name.endsWith(".cc") || name.endsWith(".cpp")) {
185 newCode.addLine(CodeGeneratorUtils.Comment("Add the" + SpecNaming.CDSSpecGeneratedHeader + " header file"));
186 newCode.addLine(CodeGeneratorUtils.IncludeHeader(SpecNaming.CDSSpecGeneratedHeader));
191 br = new BufferedReader(new FileReader(file));
192 lineReader = new LineNumberReader(br);
193 while ((curLine = lineReader.readLine()) != null) {
194 lineNum = lineReader.getLineNumber();
195 InterfaceConstruct construct = null;
196 if ((construct = renamedLinesMap.get(lineNum)) != null) {
198 String newLine = construct.getFunctionHeader()
199 .getRenamedFuncLine();
200 newCode.addLine(newLine);
202 // First add the current line
203 newCode.addLine(curLine);
204 // Then check if we need to add code
205 if (curAddition != null
206 && lineNum == curAddition.insertingLine) {
207 // Need to insert code
208 newCode.addLines(curAddition.code);
209 // Increase to the next code addition
211 curAddition = additionIdx == additions.codeAdditions
212 .size() ? null : additions.codeAdditions
217 // Write new code change to destination
218 CodeGeneratorUtils.write2File(dest, newCode.lines);
219 // System.out.println("/*************** " + file.getName()
220 // + " *************/");
221 // System.out.println(newCode);
222 } catch (FileNotFoundException e) {
224 } catch (IOException e) {
231 * This function is the main interface for the CodeGenerator class. After
232 * constructing a CodeGenerator object, users can call this function to
233 * complete the code generation and file writing process.
236 public void generateCode() {
237 // Extract all the code additions and line change
240 // Generate the header file and CPP file
241 Code generatedHeader = CodeGeneratorUtils
242 .GenerateCDSSpecHeaderFile(extractor);
243 Code generatedCPP = CodeGeneratorUtils
244 .GenerateCDSSpecCPPFile(extractor);
246 .write2File(generatedDir + SpecNaming.CDSSpecGeneratedName
247 + ".h", generatedHeader.lines);
248 CodeGeneratorUtils.write2File(generatedDir
249 + SpecNaming.CDSSpecGeneratedCPP, generatedCPP.lines);
251 // Iterate over each file
252 for (int i = 0; i < files.size(); i++) {
253 File file = files.get(i);
254 CodeAdditions additions = allAdditions.get(i);
255 HashMap<Integer, InterfaceConstruct> renamedLinesMap = renamedLinesMapList
257 writeCodeChange(file, additions, renamedLinesMap);
263 * This is just a testing function that outputs the generated code, but not
264 * actually write them to the disk.
267 private void testGenerator() {
268 // Test code generation
269 Code generatedHeader = CodeGeneratorUtils
270 .GenerateCDSSpecHeaderFile(extractor);
271 Code generatedCPP = CodeGeneratorUtils
272 .GenerateCDSSpecCPPFile(extractor);
274 System.out.println("/***** Generated header file *****/");
275 System.out.println(generatedHeader);
276 System.out.println("/***** Generated cpp file *****/");
277 System.out.println(generatedCPP);
279 for (File file : extractor.OPListMap.keySet()) {
280 ArrayList<OPConstruct> list = extractor.OPListMap.get(file);
281 for (OPConstruct con : list) {
282 Code code = CodeGeneratorUtils.Generate4OPConstruct(con);
283 System.out.println("/***** *****/");
284 System.out.println(con.annotation);
285 System.out.println(code);
289 for (File f : extractor.entryMap.keySet()) {
290 EntryConstruct con = extractor.entryMap.get(f);
291 System.out.println("/***** *****/");
292 System.out.println(con.annotation);
293 System.out.println(CodeGeneratorUtils.Generate4Entry(con));
296 for (File file : extractor.interfaceListMap.keySet()) {
297 ArrayList<InterfaceConstruct> list = extractor.interfaceListMap
299 for (InterfaceConstruct con : list) {
300 Code code = CodeGeneratorUtils.GenerateInterfaceWrapper(con);
301 System.out.println("/***** Interface wrapper *****/");
302 System.out.println(con.getFunctionHeader().getHeaderLine());
304 .println(con.getFunctionHeader().getRenamedFuncLine());
305 System.out.println(code);
310 public ArrayList<File> getSrcFiles(String dirName)
311 throws FileNotFoundException {
312 ArrayList<File> res = new ArrayList<File>();
313 File dir = new File(dirName);
314 if (dir.isDirectory() && dir.exists()) {
315 for (String file : dir.list()) {
316 if (file.endsWith(".h") || file.endsWith(".c")
317 || file.endsWith(".cc") || file.endsWith(".cpp")) {
318 res.add(new File(dir.getAbsolutePath() + "/" + file));
322 throw new FileNotFoundException(dirName
323 + " is not a valid directory!");
328 static public void main(String[] args) {
330 String[] dirNames = args;
331 // String[] dirNames = Environment.Benchmarks;
333 for (int i = 0; i < dirNames.length; i++) {
334 String dirName = dirNames[i];
335 System.out.println("/********** Generating CDSSpec files for " + dirName
337 CodeGenerator generator = new CodeGenerator(dirName);
338 generator.generateCode();