Added tree adaptor for new AST node type
[charm.git] / src / langs / charj / src / charj / translator / Translator.java
1 /***
2 ***/
3
4 package charj.translator;
5
6 import java.io.*;
7 import org.antlr.runtime.*;
8 import org.antlr.runtime.tree.*;
9 import org.antlr.stringtemplate.*;
10
11
12 /**
13  * Driver class for lexing, parsing, and output.
14  * Takes in file names, parses them and generates code
15  * for .ci and .cc files in a .charj directory. Invokes
16  * charmc on these outputs and moves any resulting .o file 
17  * to the appropriate directory.
18  */
19 public class Translator {
20
21     // template file locations
22     public static final String templateFile = "charj/translator/Charj.stg";
23
24     // variables controlled by command-line arguments
25     public String m_charmc;
26     public boolean m_debug;
27     public boolean m_verbose;
28     public boolean m_errorCondition;
29
30     public Translator(
31             String _charmc,
32             boolean _debug,
33             boolean _verbose)
34     {
35         m_charmc = _charmc;
36         m_debug = _debug;
37         m_verbose = _verbose;
38         m_errorCondition = false;
39     }
40
41     public static TreeAdaptor adaptor = new CommonTreeAdaptor() {
42         public Object create(Token token) {
43             return new CharjAST(token);
44         }
45         
46         public Object dupNode(Object t) {
47             if (t == null) {
48                 return null;
49             }
50             return create(((CharjAST)t).token);
51         }
52     };
53
54     public String translate(String filename) throws Exception 
55     {
56         ANTLRFileStream input = new ANTLRFileStream(filename);
57             
58         CharjLexer lexer = new CharjLexer(input);
59         String ciOutput = translationPass(lexer, OutputMode.ci);
60         writeTempFile(filename, ciOutput, OutputMode.ci);
61
62         input.seek(0);
63         String hOutput = translationPass(lexer, OutputMode.h);
64         writeTempFile(filename, hOutput, OutputMode.h);
65         
66         input.seek(0);
67         String ccOutput = translationPass(lexer, OutputMode.cc);
68         writeTempFile(filename, ccOutput, OutputMode.cc);
69         compileTempFiles(filename, m_charmc);
70
71         // Build a string representing all emitted code. This will be printed
72         // by the main driver if requested via command-line argument. 
73         String ciHeader = "-----CI----------------------------\n";
74         String hHeader  = "-----H-----------------------------\n";
75         String ccHeader = "-----CC----------------------------\n";
76         String footer   = "-----------------------------------\n";
77         return ciHeader + ciOutput + hHeader + hOutput + 
78             ccHeader + ccOutput + footer;
79     }
80
81     private String translationPass(
82             CharjLexer lexer, 
83             OutputMode m) throws
84         RecognitionException, IOException, InterruptedException
85     {
86         // Use lexer tokens to feed tree parser
87         CommonTokenStream tokens = new CommonTokenStream(lexer);
88         CharjParser parser = new CharjParser(tokens);
89         parser.setTreeAdaptor(adaptor);
90         CharjParser.charjSource_return r = parser.charjSource();
91
92         // Create node stream for emitters
93         CommonTree t = (CommonTree)r.getTree();
94         CommonTreeNodeStream nodes = new CommonTreeNodeStream(t);
95         nodes.setTokenStream(tokens);
96         nodes.setTreeAdaptor(adaptor);
97
98         String output = emit(nodes, m);
99         return output;
100     }
101
102     /**
103      * Utility function to write a generated .ci or .cc
104      * file to disk. Takes a .cj filename and writes a .cc
105      * or .ci file to the .charj directory depending on
106      * the OutputMode.
107      */
108     private void writeTempFile(
109             String filename, 
110             String output,
111             OutputMode m) throws
112         IOException
113     {
114         int lastDot = filename.lastIndexOf(".");
115         int lastSlash = filename.lastIndexOf("/");
116         String tempFile = filename.substring(0, lastSlash + 1) + ".charj/";
117         new File(tempFile).mkdir();
118         tempFile += filename.substring(lastSlash + 1, lastDot) + m.extension();
119         if (m_verbose) System.out.println(" [charjc] create: " + tempFile);
120         FileWriter fw = new FileWriter(tempFile);
121         fw.write(output);
122         fw.close();
123         return;
124     }
125
126     /**
127      * Enters the .charj directory and compiles the .cc and .ci files 
128      * generated from the given filename. The given charmc string 
129      * includes all options to be passed to charmc. Any generated .o 
130      * file is moved back to the initial directory.
131      */
132     private void compileTempFiles(
133             String filename,
134             String charmc) throws
135         IOException, InterruptedException
136     {
137         int lastDot = filename.lastIndexOf(".");
138         int lastSlash = filename.lastIndexOf("/");
139         String baseDirectory = filename.substring(0, lastSlash + 1);
140         if (baseDirectory.equals("")) {
141             baseDirectory = "./";
142         }
143         String tempDirectory = baseDirectory + ".charj/";
144         String moduleName = filename.substring(lastSlash + 1, lastDot);
145         String baseTempFilename = tempDirectory + moduleName;
146
147         // Compile interface file
148         String cmd = charmc + " " + baseTempFilename + ".ci";
149         File currentDir = new File(".");
150         int retVal = exec(cmd, currentDir);
151         if (retVal != 0) {
152             error("Could not compile generated interface file");
153             return;
154         }
155
156         // Move decl.h and def.h into temp directory.
157         // charmxi/charmc doesn't offer control over where to generate these
158         cmd = "mv " + moduleName + ".decl.h " + moduleName + ".def.h " +
159             tempDirectory;
160         retVal = exec(cmd, currentDir);
161          if (retVal != 0) {
162             error("Could not move .decl.h and .def.h files " +
163                     "into temp directory");
164             return;
165         }       
166
167         // Compile c++ output
168         cmd = charmc + " -c " + baseTempFilename + ".cc" + 
169             " -o " + baseTempFilename + ".o";
170         retVal = exec(cmd, currentDir);
171         if (retVal != 0) {
172             error("Could not compile generated C++ file");
173             return;
174         }
175
176         // move generated .o and .h file into .cj directory
177         cmd = "mv -f " + baseTempFilename + ".o " + baseDirectory;
178         exec(cmd, currentDir);
179         cmd = "cp -f " + baseTempFilename + ".h " + baseDirectory;
180         exec(cmd, currentDir);
181     }
182
183     /**
184      * Utility function to execute a given command line.
185      */
186     private int exec(String cmd, File outputDir) throws
187         IOException, InterruptedException
188     {
189         if (m_verbose) System.out.println(" [charjc] exec: " + cmd);
190         Process p = Runtime.getRuntime().exec(cmd, null, outputDir);
191         StreamEmitter stdout = new StreamEmitter(
192                 p.getInputStream(), System.out);
193         StreamEmitter stderr = new StreamEmitter(
194                 p.getErrorStream(), System.err);
195         stdout.start();
196         stderr.start();
197         p.waitFor();
198         stdout.join();
199         stderr.join();
200         int retVal = p.exitValue();
201         return retVal;
202     }
203
204     private String emit(
205             CommonTreeNodeStream nodes, 
206             OutputMode m) throws
207         RecognitionException, IOException, InterruptedException
208     {
209         CharjEmitter emitter = new CharjEmitter(nodes);
210         StringTemplateGroup templates = getTemplates(templateFile);
211         emitter.setTemplateLib(templates);
212         StringTemplate st = (StringTemplate)emitter.charjSource(m).getTemplate();
213         return st.toString();
214     }
215
216     private StringTemplateGroup getTemplates(String templateFile)
217     {
218         StringTemplateGroup templates = null;
219         try {
220             ClassLoader loader = Thread.currentThread().getContextClassLoader();
221             InputStream istream = loader.getResourceAsStream(templateFile);
222             BufferedReader reader = 
223                 new BufferedReader(new InputStreamReader(istream));
224             templates = new StringTemplateGroup(reader);
225             reader.close();
226         } catch(IOException ex) {
227             error("Failed to load template file", ex); 
228         }
229         return templates;
230     }
231     
232     private void error(
233             String sourceName, 
234             String msg, 
235             CommonTree node) 
236     {
237         m_errorCondition = true;
238         String linecol = ":";
239         if ( node!=null ) {
240             CommonToken t = (CommonToken)node.getToken();
241             linecol = ": line " + t.getLine() + ":" + t.getCharPositionInLine();
242         }
243         System.err.println(sourceName + linecol + " " + msg);
244         System.err.flush();
245     }
246
247
248     private void error(
249             String sourceName, 
250             String msg) {
251         error(sourceName, msg, (CommonTree)null);
252     }
253
254
255     public void error(String msg) {
256         error(" [charjc] error", msg, (CommonTree)null);
257     }
258
259
260     public void error(
261             String msg, 
262             Exception e) {
263         error(msg);
264         e.printStackTrace(System.err);
265     }
266 }