minor fix
[cdsspec-compiler.git] / src / edu / uci / eecs / specCompiler / codeGenerator / CodeGenerator.java
1 package edu.uci.eecs.specCompiler.codeGenerator;
2
3 import java.io.BufferedReader;
4 import java.io.File;
5 import java.io.FileNotFoundException;
6 import java.io.FileReader;
7 import java.io.IOException;
8 import java.util.ArrayList;
9 import java.util.Collections;
10 import java.util.HashMap;
11 import java.util.HashSet;
12 import java.util.Iterator;
13
14 import edu.uci.eecs.specCompiler.specExtraction.CPDefineCheckConstruct;
15 import edu.uci.eecs.specCompiler.specExtraction.CPDefineConstruct;
16 import edu.uci.eecs.specCompiler.specExtraction.ClassEndConstruct;
17 import edu.uci.eecs.specCompiler.specExtraction.ConditionalInterface;
18 import edu.uci.eecs.specCompiler.specExtraction.Construct;
19 import edu.uci.eecs.specCompiler.specExtraction.EntryPointConstruct;
20 import edu.uci.eecs.specCompiler.specExtraction.GlobalConstruct;
21 import edu.uci.eecs.specCompiler.specExtraction.IDExtractor;
22 import edu.uci.eecs.specCompiler.specExtraction.InterfaceConstruct;
23 import edu.uci.eecs.specCompiler.specExtraction.InterfaceDefineConstruct;
24 import edu.uci.eecs.specCompiler.specExtraction.ParserUtils;
25 import edu.uci.eecs.specCompiler.specExtraction.PotentialCPDefineConstruct;
26 import edu.uci.eecs.specCompiler.specExtraction.SequentialDefineSubConstruct;
27 import edu.uci.eecs.specCompiler.specExtraction.SourceFileInfo;
28 import edu.uci.eecs.specCompiler.specExtraction.SpecExtractor;
29
30 /**
31  * <p>
32  * This class will generate the annotated C code that can run on the current
33  * model checker.
34  * </p>
35  * 
36  * @author peizhaoo
37  * 
38  */
39 public class CodeGenerator {
40         private SemanticsChecker _semantics;
41         private SpecExtractor _extractor;
42
43         private File[] srcFiles;
44
45         private HashMap<File, SourceFileInfo> srcFilesInfo;
46
47         private HashMap<File, ArrayList<CodeAddition>> codeAdditions;
48
49         public CodeGenerator(File[] srcFiles) {
50                 this.srcFiles = srcFiles;
51                 _extractor = new SpecExtractor();
52                 _extractor.extract(srcFiles);
53
54                 this.srcFilesInfo = _extractor.srcFilesInfo;
55
56                 this.codeAdditions = new HashMap<File, ArrayList<CodeAddition>>();
57
58                 _semantics = new SemanticsChecker(_extractor);
59                 try {
60                         _semantics.check();
61                         System.out.println(_semantics);
62                 } catch (SemanticsCheckerException e) {
63                         e.printStackTrace();
64                 }
65         }
66
67         /**
68          * <p>
69          * Generate all the global code, including the "@DefineVar" in each
70          * "@Interface" define
71          * </p>
72          */
73         private void globalConstruct2Code(GlobalConstruct construct) {
74                 ArrayList<String> newCode = CodeVariables.generateGlobalVarDeclaration(
75                                 _semantics, construct);
76                 // Add it to the codeAdditions
77                 if (!codeAdditions.containsKey(construct.file)) {
78                         codeAdditions.put(construct.file, new ArrayList<CodeAddition>());
79                 }
80                 CodeAddition addition = new CodeAddition(construct.beginLineNum,
81                                 newCode);
82                 codeAdditions.get(construct.file).add(addition);
83                 newCode = CodeVariables.generateStaticVarDefine(_semantics, construct);
84                 if (newCode.size() > 0) {
85                         addition = new CodeAddition(
86                                         _semantics.getClassEndConstruct().beginLineNum, newCode);
87                         codeAdditions.get(construct.file).add(addition);
88                 }
89         }
90
91         // Wrap the interface and then renaem it
92         private void interface2Code(InterfaceConstruct construct) {
93                 // If there's no define construct for it, we generate the wrapper just
94                 // in place without declaration
95                 InterfaceDefineConstruct defineConstruct = _semantics.interfaceName2DefineConstruct
96                                 .get(construct.name);
97                 ArrayList<String> newCode;
98                 int lineNum;
99                 CodeAddition addition;
100                 // Then generate the wrapper if necessary
101                 if (defineConstruct != null) { // Need to have a wrapper declaration
102                         newCode = CodeVariables.generateInterfaceWrapperDeclaration(
103                                         _semantics, construct);
104                         lineNum = construct.beginLineNum;
105                         // Add the wrapper declaration
106                         addition = new CodeAddition(lineNum, newCode);
107                         if (!codeAdditions.containsKey(construct.file)) {
108                                 codeAdditions
109                                                 .put(construct.file, new ArrayList<CodeAddition>());
110                         }
111                         codeAdditions.get(construct.file).add(addition);
112
113                         // Add the wrapper definition
114                         newCode = CodeVariables.generateInterfaceWrapperDefinition(
115                                         _semantics, construct);
116                         lineNum = defineConstruct.beginLineNum;
117                         // Add the wrapper declaration
118                         addition = new CodeAddition(lineNum, newCode);
119                         if (!codeAdditions.containsKey(defineConstruct.file)) {
120                                 codeAdditions.put(defineConstruct.file,
121                                                 new ArrayList<CodeAddition>());
122                         }
123                         codeAdditions.get(defineConstruct.file).add(addition);
124                 } else { // No declaration needed
125                         // Last generate the definition
126                         newCode = CodeVariables.generateInterfaceWrapperDefinition(
127                                         _semantics, construct);
128                         lineNum = construct.beginLineNum;
129                         // Add the wrapper declaration
130                         addition = new CodeAddition(lineNum, newCode);
131                         if (!codeAdditions.containsKey(construct.file)) {
132                                 codeAdditions
133                                                 .put(construct.file, new ArrayList<CodeAddition>());
134                         }
135                         codeAdditions.get(construct.file).add(addition);
136                 }
137
138                 // Don't forget to rename the interface
139                 CodeVariables.renameInterface(_semantics, construct);
140         }
141
142         private void potentialCPDefine2Code(PotentialCPDefineConstruct construct) {
143                 int lineNum = construct.beginLineNum;
144                 ArrayList<String> newCode = CodeVariables.generatePotentialCPDefine(
145                                 _semantics, construct);
146
147                 CodeAddition addition = new CodeAddition(lineNum, newCode);
148                 if (!codeAdditions.containsKey(construct.file)) {
149                         codeAdditions.put(construct.file, new ArrayList<CodeAddition>());
150                 }
151                 codeAdditions.get(construct.file).add(addition);
152         }
153
154         private void CPDefine2Code(CPDefineConstruct construct) {
155                 int lineNum = construct.beginLineNum;
156                 ArrayList<String> newCode = CodeVariables.generateCPDefine(_semantics,
157                                 construct);
158
159                 CodeAddition addition = new CodeAddition(lineNum, newCode);
160                 if (!codeAdditions.containsKey(construct.file)) {
161                         codeAdditions.put(construct.file, new ArrayList<CodeAddition>());
162                 }
163                 codeAdditions.get(construct.file).add(addition);
164         }
165
166         private void CPDefineCheck2Code(CPDefineCheckConstruct construct) {
167                 int lineNum = construct.beginLineNum;
168                 ArrayList<String> newCode = CodeVariables.generateCPDefineCheck(
169                                 _semantics, construct);
170
171                 CodeAddition addition = new CodeAddition(lineNum, newCode);
172                 if (!codeAdditions.containsKey(construct.file)) {
173                         codeAdditions.put(construct.file, new ArrayList<CodeAddition>());
174                 }
175                 codeAdditions.get(construct.file).add(addition);
176         }
177
178         private void EntryPoint2Code(EntryPointConstruct construct) {
179                 int lineNum = construct.beginLineNum;
180                 ArrayList<String> newCode = new ArrayList<String>();
181                 newCode.addAll(CodeVariables.generateEntryPointInitCall());
182
183                 CodeAddition addition = new CodeAddition(lineNum, newCode);
184                 if (!codeAdditions.containsKey(construct.file)) {
185                         codeAdditions.put(construct.file, new ArrayList<CodeAddition>());
186                 }
187                 codeAdditions.get(construct.file).add(addition);
188         }
189
190         private ArrayList<String> insertAnnotation2Src(
191                         ArrayList<CodeAddition> additions, ArrayList<String> content) {
192                 int totalSize = content.size();
193                 for (int i = 0; i < additions.size(); i++) {
194                         totalSize += additions.size();
195                 }
196                 ArrayList<String> newContent = new ArrayList<String>(totalSize);
197                 int curSrcLine = 0;
198                 for (int i = 0; i < additions.size(); i++) {
199                         CodeAddition addition = additions.get(i);
200                         if (curSrcLine < addition.lineNum) {
201                                 // Be careful, subList is the interval [begin, end)
202                                 newContent
203                                                 .addAll(content.subList(curSrcLine, addition.lineNum));
204                                 curSrcLine = addition.lineNum;
205                         }
206                         newContent.addAll(addition.newCode);
207                 }
208                 newContent.addAll(content.subList(curSrcLine, content.size()));
209                 return newContent;
210         }
211
212         public void generateCode() {
213                 for (int i = 0; i < _semantics.constructs.size(); i++) {
214                         Construct construct = _semantics.constructs.get(i);
215                         if (construct instanceof GlobalConstruct) {
216                                 globalConstruct2Code((GlobalConstruct) construct);
217                         } else if (construct instanceof InterfaceConstruct) {
218                                 interface2Code((InterfaceConstruct) construct);
219                         } else if (construct instanceof PotentialCPDefineConstruct) {
220                                 potentialCPDefine2Code((PotentialCPDefineConstruct) construct);
221                         } else if (construct instanceof CPDefineConstruct) {
222                                 CPDefine2Code((CPDefineConstruct) construct);
223                         } else if (construct instanceof CPDefineCheckConstruct) {
224                                 CPDefineCheck2Code((CPDefineCheckConstruct) construct);
225                         } else if (construct instanceof EntryPointConstruct) {
226                                 EntryPoint2Code((EntryPointConstruct) construct);
227                         }
228                 }
229                 // Sort code additions
230                 HashSet<String> headers = CodeVariables.getAllHeaders(_semantics);
231                 ArrayList<String> headerCode = new ArrayList<String>(headers.size());
232                 for (String header : headers) {
233                         headerCode.add("#include " + header);
234                 }
235                 for (File file : codeAdditions.keySet()) {
236                         ArrayList<CodeAddition> additions = codeAdditions.get(file);
237                         
238                         if (additions.size() == 0) // Simply do nothing
239                                 continue;
240                         ArrayList<String> content = _semantics.srcFilesInfo.get(file).content;
241                         Collections.sort(additions, CodeAddition.lineNumComparator);
242                         // Insert generated annotation to the source files
243                         ArrayList<String> newContent = insertAnnotation2Src(additions,
244                                         content);
245                         ArrayList<String> finalContent = new ArrayList<String>(headerCode.size() + newContent.size());
246                         finalContent.addAll(headerCode);
247                         finalContent.addAll(newContent);
248                         // Write it back to file
249                         ParserUtils.write2File(file, finalContent);
250                 }
251
252         }
253
254         public static void main(String[] argvs) {
255                 String homeDir = Environment.HOME_DIRECTORY;
256                 File[] srcFiles = {
257 //                               new File(homeDir + "/benchmark/linuxrwlocks/linuxrwlocks.c")
258 //                               };
259                                 // new File(homeDir
260                                 // +
261                                 // "/benchmark/cliffc-hashtable/simplified_cliffc_hashtable.h"),
262                                 // };
263 //                              new File(homeDir + "/benchmark/ms-queue/my_queue.c"),
264 //                              new File(homeDir + "/benchmark/ms-queue/main.c"),
265 //                              new File(homeDir + "/benchmark/ms-queue/my_queue.h") };
266                 
267                  new File(homeDir + "/benchmark/read-copy-update/rcu.cc") };
268                 CodeGenerator gen = new CodeGenerator(srcFiles);
269                 gen.generateCode();
270         }
271 }