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.EntryConstruct;
17 import edu.uci.eecs.specExtraction.InterfaceConstruct;
18 import edu.uci.eecs.specExtraction.OPConstruct;
19 import edu.uci.eecs.specExtraction.SpecExtractor;
20 import edu.uci.eecs.specExtraction.SpecNaming;
21 import edu.uci.eecs.specExtraction.WrongAnnotationException;
22 import edu.uci.eecs.utilParser.ParseException;
26 * This class represents the engine to generate instrumented code. To construct
27 * an object of this file, users need provide a string that represents the
28 * sub-directory under the benchmarks directory, then the engine will explore
29 * all the C/C++ files that ends with ".cc/.cpp/.c/.h" and extract specification
30 * annotations and generate instrumented code in the generated directory.
36 public class CodeGenerator {
37 // Files that we need to process
38 private ArrayList<File> files;
40 // Code addition list --- per file
41 private ArrayList<CodeAdditions> allAdditions;
42 // Line change map list --- per file; Each map represents the
43 // line->InterfaceConstruct mapping that will rename the interface
45 private ArrayList<HashMap<Integer, InterfaceConstruct>> renamedLinesMapList;
47 // The string that users provide as a sub-directory in the benchmarks
48 // directory: e.g. ms-queue
49 public final String dirName;
51 // The original directory --- the benchmarks directory: e.g.
52 // ~/model-checker/benchmarks/
53 public final String originalDir;
54 // The directory for generated files: e.g. ~/model-checker/test-cdsspec/
55 public final String generatedDir;
57 // The specification annotation extractor
58 private SpecExtractor extractor;
60 public CodeGenerator(String dirName) {
61 this.dirName = dirName;
62 originalDir = Environment.BenchmarksDir + dirName + "/";
63 generatedDir = Environment.GeneratedFilesDir + dirName + "/";
65 files = this.getSrcFiles(originalDir);
66 } catch (FileNotFoundException e) {
69 extractor = new SpecExtractor();
71 extractor.extract(files);
72 } catch (WrongAnnotationException e) {
74 } catch (ParseException e) {
81 * This function initializes the list of code additions and line changes for
82 * all the files. For the code additions of a file, we sort them in an
83 * increasing order by the inserting line number.
87 private void getAllCodeChanges() {
88 allAdditions = new ArrayList<CodeAdditions>();
89 renamedLinesMapList = new ArrayList<HashMap<Integer, InterfaceConstruct>>();
90 for (int i = 0; i < files.size(); i++) {
91 File file = files.get(i);
92 // One CodeAdditions per file
93 CodeAdditions additions = new CodeAdditions(file);
94 // Add the additions for this file to the list
95 allAdditions.add(additions);
97 // One CodeChange per file
98 HashMap<Integer, InterfaceConstruct> renamedLinesMap = new HashMap<Integer, InterfaceConstruct>();
99 // Add it the the list
100 renamedLinesMapList.add(renamedLinesMap);
102 // Extract all the additions
103 ArrayList<OPConstruct> OPList = extractor.OPListMap.get(file);
104 EntryConstruct entry = extractor.entryMap.get(file);
105 ArrayList<InterfaceConstruct> interfaceList = extractor.interfaceListMap
108 CodeAddition addition = null;
109 // For ordering point constructs
110 if (OPList != null) {
111 for (OPConstruct con : OPList) {
112 code = CodeGeneratorUtils.Generate4OPConstruct(con);
113 addition = new CodeAddition(con.beginLineNum, code);
114 additions.addCodeAddition(addition);
117 // For entry constructs
119 code = CodeGeneratorUtils.Generate4Entry(entry);
120 addition = new CodeAddition(entry.beginLineNum, code);
121 additions.addCodeAddition(addition);
123 // For interface constructs
124 if (interfaceList != null) {
125 for (InterfaceConstruct con : interfaceList) {
126 code = CodeGeneratorUtils.GenerateInterfaceWrapper(con);
127 addition = new CodeAddition(con.getEndLineNumFunction(),
129 additions.addCodeAddition(addition);
130 // Record the line to be changed
131 renamedLinesMap.put(con.endLineNum + 1, con);
135 // Sort additions by line number increasingly
142 * For a specific file, given the code additions and line changes mapping
143 * for that file, this function will generate the new code for that file and
144 * write it back to the destination directory.
148 * The file to be processed
150 * The sorted code additions for the file
151 * @param renamedLinesMap
152 * The line change mapping for the file
154 private void writeCodeChange(File file, CodeAdditions additions,
155 HashMap<Integer, InterfaceConstruct> renamedLinesMap) {
156 Code newCode = new Code();
157 BufferedReader br = null;
158 LineNumberReader lineReader = null;
160 String curLine = null;
162 String dest = generatedDir + file.getName();
163 CodeAddition curAddition = null;
164 int additionIdx = -1;
165 if (!additions.isEmpty()) {
167 curAddition = additions.codeAdditions.get(0);
171 br = new BufferedReader(new FileReader(file));
172 lineReader = new LineNumberReader(br);
173 while ((curLine = lineReader.readLine()) != null) {
174 lineNum = lineReader.getLineNumber();
175 InterfaceConstruct construct = null;
176 if ((construct = renamedLinesMap.get(lineNum)) != null) {
178 String newLine = construct.getFunctionHeader()
179 .getRenamedFuncLine();
180 newCode.addLine(newLine);
182 // First add the current line
183 newCode.addLine(curLine);
184 // Then check if we need to add code
185 if (curAddition != null
186 && lineNum == curAddition.insertingLine) {
187 // Need to insert code
188 newCode.addLines(curAddition.code);
189 // Increase to the next code addition
191 curAddition = additionIdx == additions.codeAdditions
192 .size() ? null : additions.codeAdditions
197 // Write new code change to destination
198 CodeGeneratorUtils.write2File(dest, newCode.lines);
199 // System.out.println("/*************** " + file.getName()
200 // + " *************/");
201 // System.out.println(newCode);
202 } catch (FileNotFoundException e) {
204 } catch (IOException e) {
211 * This function is the main interface for the CodeGenerator class. After
212 * constructing a CodeGenerator object, users can call this function to
213 * complete the code generation and file writing process.
216 public void generateCode() {
217 // Extract all the code additions and line change
220 // Generate the header file and CPP file
221 Code generatedHeader = CodeGeneratorUtils
222 .GenerateCDSSpecHeaderFile(extractor);
223 Code generatedCPP = CodeGeneratorUtils
224 .GenerateCDSSpecCPPFile(extractor);
226 .write2File(generatedDir + SpecNaming.CDSSpecGeneratedName
227 + ".h", generatedHeader.lines);
228 CodeGeneratorUtils.write2File(generatedDir
229 + SpecNaming.CDSSpecGeneratedCPP, generatedCPP.lines);
231 // Iterate over each file
232 for (int i = 0; i < files.size(); i++) {
233 File file = files.get(i);
234 CodeAdditions additions = allAdditions.get(i);
235 HashMap<Integer, InterfaceConstruct> renamedLinesMap = renamedLinesMapList
237 writeCodeChange(file, additions, renamedLinesMap);
243 * This is just a testing function that outputs the generated code, but not
244 * actually write them to the disk.
247 private void testGenerator() {
248 // Test code generation
249 Code generatedHeader = CodeGeneratorUtils
250 .GenerateCDSSpecHeaderFile(extractor);
251 Code generatedCPP = CodeGeneratorUtils
252 .GenerateCDSSpecCPPFile(extractor);
254 System.out.println("/***** Generated header file *****/");
255 System.out.println(generatedHeader);
256 System.out.println("/***** Generated cpp file *****/");
257 System.out.println(generatedCPP);
259 for (File file : extractor.OPListMap.keySet()) {
260 ArrayList<OPConstruct> list = extractor.OPListMap.get(file);
261 for (OPConstruct con : list) {
262 Code code = CodeGeneratorUtils.Generate4OPConstruct(con);
263 System.out.println("/***** *****/");
264 System.out.println(con.annotation);
265 System.out.println(code);
269 for (File f : extractor.entryMap.keySet()) {
270 EntryConstruct con = extractor.entryMap.get(f);
271 System.out.println("/***** *****/");
272 System.out.println(con.annotation);
273 System.out.println(CodeGeneratorUtils.Generate4Entry(con));
276 for (File file : extractor.interfaceListMap.keySet()) {
277 ArrayList<InterfaceConstruct> list = extractor.interfaceListMap
279 for (InterfaceConstruct con : list) {
280 Code code = CodeGeneratorUtils.GenerateInterfaceWrapper(con);
281 System.out.println("/***** Interface wrapper *****/");
282 System.out.println(con.getFunctionHeader().getHeaderLine());
284 .println(con.getFunctionHeader().getRenamedFuncLine());
285 System.out.println(code);
290 public ArrayList<File> getSrcFiles(String dirName)
291 throws FileNotFoundException {
292 ArrayList<File> res = new ArrayList<File>();
293 File dir = new File(dirName);
294 if (dir.isDirectory() && dir.exists()) {
295 for (String file : dir.list()) {
296 if (file.endsWith(".h") || file.endsWith(".c")
297 || file.endsWith(".cc") || file.endsWith(".cpp")) {
298 res.add(new File(dir.getAbsolutePath() + "/" + file));
302 throw new FileNotFoundException(dirName
303 + " is not a valid directory!");
308 static public void main(String[] args) {
309 String[] dirNames = { Environment.REGISTER, Environment.MS_QUEUE, Environment.LINUXRWLOCKS, Environment.MCS_LOCK, Environment.DEQUE };
311 for (int i = 0; i < dirNames.length; i++) {
312 String dirName = dirNames[i];
313 System.out.println("/********** Processing " + dirName
315 CodeGenerator generator = new CodeGenerator(dirName);
316 generator.generateCode();