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
64 generatedDir = Environment.GeneratedFilesDir + dirName
67 files = this.getSrcFiles(originalDir);
68 } catch (FileNotFoundException e) {
71 extractor = new SpecExtractor();
73 extractor.extract(files);
74 } catch (WrongAnnotationException e) {
76 } catch (ParseException e) {
83 * This function initializes the list of code additions and line changes for
84 * all the files. For the code additions of a file, we sort them in an
85 * increasing order by the inserting line number.
89 private void getAllCodeChanges() {
90 allAdditions = new ArrayList<CodeAdditions>();
91 renamedLinesMapList = new ArrayList<HashMap<Integer, InterfaceConstruct>>();
92 for (int i = 0; i < files.size(); i++) {
93 File file = files.get(i);
94 // One CodeAdditions per file
95 CodeAdditions additions = new CodeAdditions(file);
96 // Add the additions for this file to the list
97 allAdditions.add(additions);
99 // One CodeChange per file
100 HashMap<Integer, InterfaceConstruct> renamedLinesMap = new HashMap<Integer, InterfaceConstruct>();
101 // Add it the the list
102 renamedLinesMapList.add(renamedLinesMap);
104 // Extract all the additions
105 ArrayList<OPConstruct> OPList = extractor.OPListMap.get(file);
106 EntryConstruct entry = extractor.entryMap.get(file);
107 ArrayList<InterfaceConstruct> interfaceList = extractor.interfaceListMap
110 CodeAddition addition = null;
111 // For ordering point constructs
112 if (OPList != null) {
113 for (OPConstruct con : OPList) {
114 code = CodeGeneratorUtils.Generate4OPConstruct(con);
115 addition = new CodeAddition(con.beginLineNum, code);
116 additions.addCodeAddition(addition);
119 // For entry constructs
121 code = CodeGeneratorUtils.Generate4Entry(entry);
122 addition = new CodeAddition(entry.beginLineNum, code);
123 additions.addCodeAddition(addition);
125 // For interface constructs
126 if (interfaceList != null) {
127 for (InterfaceConstruct con : interfaceList) {
128 code = CodeGeneratorUtils.GenerateInterfaceWrapper(con);
129 addition = new CodeAddition(con.getEndLineNumFunction(),
131 additions.addCodeAddition(addition);
132 // Record the line to be changed
133 renamedLinesMap.put(con.endLineNum + 1, con);
137 // Sort additions by line number increasingly
144 * For a specific file, given the code additions and line changes mapping
145 * for that file, this function will generate the new code for that file and
146 * write it back to the destination directory.
150 * The file to be processed
152 * The sorted code additions for the file
153 * @param renamedLinesMap
154 * The line change mapping for the file
156 private void writeCodeChange(File file, CodeAdditions additions,
157 HashMap<Integer, InterfaceConstruct> renamedLinesMap) {
158 Code newCode = new Code();
159 BufferedReader br = null;
160 LineNumberReader lineReader = null;
162 String curLine = null;
164 String dest = generatedDir + file.getName();
165 CodeAddition curAddition = null;
166 int additionIdx = -1;
167 if (!additions.isEmpty()) {
169 curAddition = additions.codeAdditions.get(0);
173 br = new BufferedReader(new FileReader(file));
174 lineReader = new LineNumberReader(br);
175 while ((curLine = lineReader.readLine()) != null) {
176 lineNum = lineReader.getLineNumber();
177 InterfaceConstruct construct = null;
178 if ((construct = renamedLinesMap.get(lineNum)) != null) {
180 String newLine = construct.getFunctionHeader()
181 .getRenamedFuncLine();
182 newCode.addLine(newLine);
184 // First add the current line
185 newCode.addLine(curLine);
186 // Then check if we need to add code
187 if (curAddition != null
188 && lineNum == curAddition.insertingLine) {
189 // Need to insert code
190 newCode.addLines(curAddition.code);
191 // Increase to the next code addition
193 curAddition = additionIdx == additions.codeAdditions
194 .size() ? null : additions.codeAdditions
199 // Write new code change to destination
200 CodeGeneratorUtils.write2File(dest, newCode.lines);
201 // System.out.println("/*************** " + file.getName()
202 // + " *************/");
203 // System.out.println(newCode);
204 } catch (FileNotFoundException e) {
206 } catch (IOException e) {
213 * This function is the main interface for the CodeGenerator class. After
214 * constructing a CodeGenerator object, users can call this function to
215 * complete the code generation and file writing process.
218 public void generateCode() {
219 // Extract all the code additions and line change
222 // Generate the header file and CPP file
223 Code generatedHeader = CodeGeneratorUtils
224 .GenerateCDSSpecHeaderFile(extractor);
225 Code generatedCPP = CodeGeneratorUtils
226 .GenerateCDSSpecCPPFile(extractor);
228 .write2File(generatedDir + SpecNaming.CDSSpecGeneratedName
229 + ".h", generatedHeader.lines);
230 CodeGeneratorUtils.write2File(generatedDir
231 + SpecNaming.CDSSpecGeneratedCPP, generatedCPP.lines);
233 // Iterate over each file
234 for (int i = 0; i < files.size(); i++) {
235 File file = files.get(i);
236 CodeAdditions additions = allAdditions.get(i);
237 HashMap<Integer, InterfaceConstruct> renamedLinesMap = renamedLinesMapList
239 writeCodeChange(file, additions, renamedLinesMap);
245 * This is just a testing function that outputs the generated code, but not
246 * actually write them to the disk.
249 private void testGenerator() {
250 // Test code generation
251 Code generatedHeader = CodeGeneratorUtils
252 .GenerateCDSSpecHeaderFile(extractor);
253 Code generatedCPP = CodeGeneratorUtils
254 .GenerateCDSSpecCPPFile(extractor);
256 System.out.println("/***** Generated header file *****/");
257 System.out.println(generatedHeader);
258 System.out.println("/***** Generated cpp file *****/");
259 System.out.println(generatedCPP);
261 for (File file : extractor.OPListMap.keySet()) {
262 ArrayList<OPConstruct> list = extractor.OPListMap.get(file);
263 for (OPConstruct con : list) {
264 Code code = CodeGeneratorUtils.Generate4OPConstruct(con);
265 System.out.println("/***** *****/");
266 System.out.println(con.annotation);
267 System.out.println(code);
271 for (File f : extractor.entryMap.keySet()) {
272 EntryConstruct con = extractor.entryMap.get(f);
273 System.out.println("/***** *****/");
274 System.out.println(con.annotation);
275 System.out.println(CodeGeneratorUtils.Generate4Entry(con));
278 for (File file : extractor.interfaceListMap.keySet()) {
279 ArrayList<InterfaceConstruct> list = extractor.interfaceListMap
281 for (InterfaceConstruct con : list) {
282 Code code = CodeGeneratorUtils.GenerateInterfaceWrapper(con);
283 System.out.println("/***** Interface wrapper *****/");
284 System.out.println(con.getFunctionHeader().getHeaderLine());
286 .println(con.getFunctionHeader().getRenamedFuncLine());
287 System.out.println(code);
292 public ArrayList<File> getSrcFiles(String dirName)
293 throws FileNotFoundException {
294 ArrayList<File> res = new ArrayList<File>();
295 File dir = new File(dirName);
296 if (dir.isDirectory() && dir.exists()) {
297 for (String file : dir.list()) {
298 if (file.endsWith(".h") || file.endsWith(".c")
299 || file.endsWith(".cc") || file.endsWith(".cpp")) {
300 res.add(new File(dir.getAbsolutePath() + "/" + file));
304 throw new FileNotFoundException(dirName
305 + " is not a valid directory!");
310 static public void main(String[] args) {
311 String dirName = Environment.MS_QUEUE;
312 CodeGenerator generator = new CodeGenerator(dirName);
313 generator.generateCode();