3 import java_cup.runtime.ComplexSymbolFactory;
4 import java_cup.runtime.ScannerBuffer;
6 import java.util.HashMap;
7 import java.util.HashSet;
12 import iotpolicy.parser.Lexer;
13 import iotpolicy.parser.Parser;
14 import iotpolicy.tree.ParseNode;
15 import iotpolicy.tree.ParseNodeVector;
16 import iotpolicy.tree.ParseTreeHandler;
17 import iotpolicy.tree.CapabilityDecl;
18 import iotpolicy.tree.InterfaceDecl;
19 import iotpolicy.tree.RequiresDecl;
21 /** Class IoTCompiler is the main stub compiler for
22 * stub files generation. This class calls helper classes
23 * such as Parser, Lexer, InterfaceDecl, CapabilityDecl,
24 * RequiresDecl, ParseTreeHandler, etc.
26 * @author Rahmadi Trimananda <rahmadi.trimananda @ uci.edu>
30 public class IoTCompiler {
35 private String origInt;
36 private ParseTreeHandler ptHandler;
37 private InterfaceDecl intDecl;
38 private CapabilityDecl capDecl;
39 private RequiresDecl reqDecl;
40 private Map<String,Set<String>> mapCapabMethods;
41 private PrintWriter pw;
47 private final static String OUTPUT_DIRECTORY = "stubfiles";
52 public IoTCompiler() {
55 ptHandler = new ParseTreeHandler();
59 mapCapabMethods = new HashMap<String,Set<String>>();
61 dir = OUTPUT_DIRECTORY;
65 public IoTCompiler(String _origInt, ParseNode _pnPol, ParseNode _pnReq) {
68 ptHandler = new ParseTreeHandler(_origInt, _pnPol, _pnReq);
72 mapCapabMethods = new HashMap<String,Set<String>>();
74 dir = OUTPUT_DIRECTORY;
79 * parsePolicyFile() parses policy file
81 * It also generates parse tree and
82 * copies useful information from parse tree into
83 * InterfaceDecl, CapabilityDecl, and RequiresDecl
85 * Additionally, the data structure handles are
86 * returned from tree-parsing for further process.
89 public void parsePolicyFile() {
91 ptHandler.processInterfaceDecl();
92 intDecl = ptHandler.getInterfaceDecl();
94 ptHandler.processCapabilityDecl();
95 capDecl = ptHandler.getCapabilityDecl();
97 ptHandler.processRequiresDecl();
98 reqDecl = ptHandler.getRequiresDecl();
103 * getMethodsForIntface() reads for methods in the data structure
105 * It is going to give list of methods for a certain interface
106 * based on the declaration of capabilities.
108 public void getMethodsForIntface() {
110 // Get set of new interfaces, e.g. CameraWithCaptureAndData
111 // Generate this new interface with all the methods it needs
112 // from different capabilities it declares
113 Set<String> setIntfaces = reqDecl.getInterfaces();
114 for (String strInt : setIntfaces) {
116 // Initialize a set of methods
117 Set<String> setMethods = new HashSet<String>();
118 // Get list of capabilities, e.g. ImageCapture, VideoRecording, etc.
119 List<String> listCapab = reqDecl.getCapabList(strInt);
120 for (String strCap : listCapab) {
122 // Get list of methods for each capability
123 List<String> listCapabMeth = capDecl.getMethods(strCap);
124 for (String strMeth : listCapabMeth) {
126 // Add methods into setMethods
127 // This is to also handle redundancies (say two capabilities
128 // share the same methods)
129 setMethods.add(strMeth);
132 // Add interface and methods information into map
133 mapCapabMethods.put(strInt, setMethods);
139 * generateJavaInterfaces() generate stub interfaces based on the methods list in Java
141 public void generateJavaInterfaces() throws IOException {
143 // Create a new directory
144 createDirectory(dir);
145 for (Map.Entry<String,Set<String>> intMeth : mapCapabMethods.entrySet()) {
147 // Open a new file to write into
148 String newIntface = intMeth.getKey();
149 FileWriter fw = new FileWriter(dir + "/" + newIntface + ".java");
150 pw = new PrintWriter(new BufferedWriter(fw));
151 // Write interface header
153 println("public interface " + newIntface + " {");
154 List<String> meths = intDecl.getMethods();
157 for (String method : intMeth.getValue()) {
159 List<String> methParams = intDecl.getMethodParams(method);
160 List<String> methPrmTypes = intDecl.getMethodParamTypes(method);
161 print("public " + intDecl.getMethodType(method) + " " +
162 intDecl.getMethodId(method) + "(");
163 for (int i = 0; i < methParams.size(); i++) {
164 print(methPrmTypes.get(i) + " " + methParams.get(i));
165 // Check if this is the last element (don't print a comma)
166 if (i != methParams.size() - 1) {
174 System.out.println("IoTCompiler: Generated interface " + newIntface + ".java...");
180 * generateCPlusInterfaces() generate stub interfaces based on the methods list in C++
182 * For C++ we use virtual classe as interface
184 public void generateCPlusInterfaces() throws IOException {
186 // Create a new directory
187 createDirectory(dir);
188 for (Map.Entry<String,Set<String>> intMeth : mapCapabMethods.entrySet()) {
190 // Open a new file to write into
191 String newIntface = intMeth.getKey();
192 FileWriter fw = new FileWriter(dir + "/" + newIntface + ".hpp");
193 pw = new PrintWriter(new BufferedWriter(fw));
194 // Write file headers
195 println("#include<iostream>");
197 println("using namespace std;");
199 println("class " + newIntface);
203 for (String method : intMeth.getValue()) {
205 List<String> methParams = intDecl.getMethodParams(method);
206 List<String> methPrmTypes = intDecl.getMethodParamTypes(method);
207 print("virtual " + convertType(intDecl.getMethodType(method)) + " " +
208 intDecl.getMethodId(method) + "(");
209 for (int i = 0; i < methParams.size(); i++) {
210 print(convertType(methPrmTypes.get(i)) + " " + methParams.get(i));
211 // Check if this is the last element (don't print a comma)
212 if (i != methParams.size() - 1) {
221 System.out.println("IoTCompiler: Generated interface " + newIntface + ".hpp...");
227 * generateJavaStubClasses() generate stubs based on the methods list in Java
229 public void generateJavaStubClasses() throws IOException {
231 // Create a new directory
232 createDirectory(dir);
233 for (Map.Entry<String,Set<String>> intMeth : mapCapabMethods.entrySet()) {
235 // Open a new file to write into
236 String newIntface = intMeth.getKey();
237 String newStubClass = newIntface + "_Stub";
238 FileWriter fw = new FileWriter(dir + "/" + newStubClass + ".java");
239 pw = new PrintWriter(new BufferedWriter(fw));
240 // Write interface header
242 println("public class " + newStubClass + " implements " + newIntface + " {");
245 for (String method : intMeth.getValue()) {
247 List<String> methParams = intDecl.getMethodParams(method);
248 List<String> methPrmTypes = intDecl.getMethodParamTypes(method);
249 print("public " + intDecl.getMethodType(method) + " " +
250 intDecl.getMethodId(method) + "(");
251 for (int i = 0; i < methParams.size(); i++) {
252 print(methPrmTypes.get(i) + " " + methParams.get(i));
253 // Check if this is the last element (don't print a comma)
254 if (i != methParams.size() - 1) {
259 // Check if this is not "void"
260 if (!intDecl.getMethodType(method).equals("void")) {
261 String retStmt = generateReturnStmt(intDecl.getMethodType(method));
262 println("return " + retStmt + ";");
269 System.out.println("IoTCompiler: Generated stub class " + newStubClass + ".java...");
275 * generateCPlusStubClasses() generate stubs based on the methods list in C++
277 public void generateCPlusStubClasses() throws IOException {
279 // Create a new directory
280 createDirectory(dir);
281 for (Map.Entry<String,Set<String>> intMeth : mapCapabMethods.entrySet()) {
283 // Open a new file to write into
284 String newIntface = intMeth.getKey();
285 String newStubClass = newIntface + "_Stub";
286 FileWriter fw = new FileWriter(dir + "/" + newStubClass + ".hpp");
287 pw = new PrintWriter(new BufferedWriter(fw));
288 // Write file headers
289 println("#include<iostream>");
290 println("#include \"" + newIntface + ".hpp\""); println("");
291 println("using namespace std;"); println("");
292 println("class " + newStubClass + " : public " + newIntface);
294 println("public:"); println("");
295 // Add default constructor and destructor
296 println(newStubClass + "() { }"); println("");
297 println("~" + newStubClass + "() { }"); println("");
299 for (String method : intMeth.getValue()) {
301 List<String> methParams = intDecl.getMethodParams(method);
302 List<String> methPrmTypes = intDecl.getMethodParamTypes(method);
303 print(convertType(intDecl.getMethodType(method)) + " " +
304 intDecl.getMethodId(method) + "(");
305 for (int i = 0; i < methParams.size(); i++) {
306 print(convertType(methPrmTypes.get(i)) + " " + methParams.get(i));
307 // Check if this is the last element (don't print a comma)
308 if (i != methParams.size() - 1) {
313 // Check if this is not "void"
314 if (!intDecl.getMethodType(method).equals("void")) {
315 String retStmt = generateReturnStmt(intDecl.getMethodType(method));
316 if (retStmt.equals("null")) { // null = NULL in C++
319 println("return " + retStmt + ";");
321 println("}"); println("");
323 print("}"); println(";");
325 System.out.println("IoTCompiler: Generated stub class " + newIntface + ".hpp...");
331 * generateReturnStmt() generate return statement based on methType
333 public String generateReturnStmt(String methType) {
335 // Generate dummy returns for now
336 if (methType.equals("short")||
337 methType.equals("int") ||
338 methType.equals("long") ||
339 methType.equals("float")||
340 methType.equals("double")) {
343 } else if ( methType.equals("String") ||
344 methType.equals("byte")) {
347 } else if ( methType.equals("char")) {
350 } else if ( methType.equals("boolean")) {
360 * setDirectory() set a new directory for stub files
362 public void setDirectory(String _dir) {
369 * printUsage() prints the usage of this compiler
371 public static void printUsage() {
373 System.out.println();
374 System.out.println("Sentinel interface and stub compiler version 1.0");
375 System.out.println("Copyright (c) 2015-2016 University of California, Irvine - Programming Language Group.");
376 System.out.println("All rights reserved.");
377 System.out.println("Usage:");
378 System.out.println("\tjava IoTCompiler --help / -h\t\t\t\t\tDisplay this help texts");
379 System.out.println("\tjava IoTCompiler <main-policy-file> <req-policy-file>\t\tGenerate both Java and C++ stub files");
380 System.out.println("\tjava IoTCompiler <main-policy-file> <req-policy-file> [options]");
381 System.out.println("Options:");
382 System.out.println("\t-java\t<directory>\tGenerate Java stub files");
383 System.out.println("\t-cplus\t<directory>\tGenerate C++ stub files");
384 System.out.println();
388 /**================================================
389 * Helper functions to write stub codes into files
390 **================================================
392 boolean newline=true;
395 private void print(String str) {
400 for(int i=0; i<tab; i++)
409 * This function converts Java to C++ type for compilation
411 private String convertType(String jType) {
413 // Generate dummy returns for now
414 if (jType.equals("short")||
415 jType.equals("int") ||
416 jType.equals("long") ||
417 jType.equals("char") ||
418 jType.equals("float")||
419 jType.equals("double")) {
422 } else if ( jType.equals("String")) {
425 } else if ( jType.equals("byte")) {
428 } else if ( jType.equals("boolean")) {
437 private void println(String str) {
442 for(int i=0; i<tab; i++)
451 private void updatetabbing(String str) {
452 tablevel+=count(str,'{')-count(str,'}');
456 private int count(String str, char key) {
457 char[] array = str.toCharArray();
459 for(int i=0; i<array.length; i++) {
467 private void createDirectory(String dirName) {
469 File file = new File(dirName);
470 if (!file.exists()) {
472 System.out.println("IoTCompiler: Directory " + dirName + " has been created!");
474 System.out.println("IoTCompiler: Failed to create directory " + dirName + "!");
477 System.out.println("IoTCompiler: Directory " + dirName + " exists...");
482 public static void main(String[] args) throws Exception {
485 if (args.length != 0) {
487 if ((args[0].equals("--help") ||
488 (args[0].equals("-h")))) {
489 IoTCompiler.printUsage();
491 // Parse main policy file
492 ComplexSymbolFactory csfPol = new ComplexSymbolFactory();
493 ScannerBuffer lexerPol =
494 new ScannerBuffer(new Lexer(new BufferedReader(new FileReader(args[0])),csfPol));
495 Parser parsePol = new Parser(lexerPol,csfPol);
496 ParseNode pnPol = (ParseNode) parsePol.parse().value;
497 // Parse "requires" policy file
498 ComplexSymbolFactory csfReq = new ComplexSymbolFactory();
499 ScannerBuffer lexerReq =
500 new ScannerBuffer(new Lexer(new BufferedReader(new FileReader(args[1])),csfReq));
501 Parser parseReq = new Parser(lexerReq,csfReq);
502 ParseNode pnReq = (ParseNode) parseReq.parse().value;
503 // Get interface name
504 String intFace = ParseTreeHandler.getOrigIntface(pnPol);
505 //System.out.println("IoTCompiler: Original interface: " + intFace);
506 IoTCompiler comp = new IoTCompiler(intFace, pnPol, pnReq);
507 // Generate all policy files if just policy file is provided
508 comp.parsePolicyFile();
509 comp.getMethodsForIntface();
510 if (args.length == 2) {
511 comp.generateJavaInterfaces();
512 comp.generateJavaStubClasses();
513 comp.generateCPlusInterfaces();
514 comp.generateCPlusStubClasses();
516 // Check other options
518 while(i < args.length) {
519 // Check whether <directory> is provided
520 if ((i + 1) < args.length) {
521 comp.setDirectory(args[i+1]);
523 throw new Error("IoTCompiler: ERROR - please provide <directory> after option: " + args[i]);
524 if (args[i].equals("-java")) {
525 comp.generateJavaInterfaces();
526 comp.generateJavaStubClasses();
527 } else if (args[i].equals("-cplus")) {
528 comp.generateCPlusInterfaces();
529 comp.generateCPlusStubClasses();
531 throw new Error("IoTCompiler: ERROR - unrecognized command line option: " + args[i]);
538 // Need at least the policy file name
539 IoTCompiler.printUsage();
540 throw new Error("IoTCompiler: At least two arguments (main and requires policy files) have to be provided!");