Initial implementation of symbols and scopes with symbol table.
[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     private String m_charmc;
26     private boolean m_debug;
27     private boolean m_verbose;
28     private 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 boolean debug()      { return m_debug; }
42     public boolean verbose()    { return m_verbose; }
43
44     public static TreeAdaptor adaptor = new CommonTreeAdaptor() {
45         public Object create(Token token) {
46             return new CharjAST(token);
47         }
48         
49         public Object dupNode(Object t) {
50             if (t == null) {
51                 return null;
52             }
53             return create(((CharjAST)t).token);
54         }
55     };
56
57     public String translate(String filename) throws Exception 
58     {
59         ANTLRFileStream input = new ANTLRFileStream(filename);
60             
61         CharjLexer lexer = new CharjLexer(input);
62         String ciOutput = translationPass(lexer, OutputMode.ci);
63         writeTempFile(filename, ciOutput, OutputMode.ci);
64
65         input.seek(0);
66         String hOutput = translationPass(lexer, OutputMode.h);
67         writeTempFile(filename, hOutput, OutputMode.h);
68         
69         input.seek(0);
70         String ccOutput = translationPass(lexer, OutputMode.cc);
71         writeTempFile(filename, ccOutput, OutputMode.cc);
72         compileTempFiles(filename, m_charmc);
73
74         // Build a string representing all emitted code. This will be printed
75         // by the main driver if requested via command-line argument. 
76         String ciHeader = "-----CI----------------------------\n";
77         String hHeader  = "-----H-----------------------------\n";
78         String ccHeader = "-----CC----------------------------\n";
79         String footer   = "-----------------------------------\n";
80         return ciHeader + ciOutput + hHeader + hOutput + 
81             ccHeader + ccOutput + footer;
82     }
83
84     private String translationPass(
85             CharjLexer lexer, 
86             OutputMode m) throws
87         RecognitionException, IOException, InterruptedException
88     {
89         // Use lexer tokens to feed tree parser
90         CommonTokenStream tokens = new CommonTokenStream(lexer);
91         CharjParser parser = new CharjParser(tokens);
92         parser.setTreeAdaptor(adaptor);
93         CharjParser.charjSource_return r = parser.charjSource();
94
95         // Create node stream for emitters
96         CommonTree t = (CommonTree)r.getTree();
97         CommonTreeNodeStream nodes = new CommonTreeNodeStream(t);
98         nodes.setTokenStream(tokens);
99         nodes.setTreeAdaptor(adaptor);
100
101         String output = emit(nodes, m);
102         return output;
103     }
104
105     /**
106      * Utility function to write a generated .ci or .cc
107      * file to disk. Takes a .cj filename and writes a .cc
108      * or .ci file to the .charj directory depending on
109      * the OutputMode.
110      */
111     private void writeTempFile(
112             String filename, 
113             String output,
114             OutputMode m) throws
115         IOException
116     {
117         int lastDot = filename.lastIndexOf(".");
118         int lastSlash = filename.lastIndexOf("/");
119         String tempFile = filename.substring(0, lastSlash + 1) + ".charj/";
120         new File(tempFile).mkdir();
121         tempFile += filename.substring(lastSlash + 1, lastDot) + m.extension();
122         if (m_verbose) System.out.println(" [charjc] create: " + tempFile);
123         FileWriter fw = new FileWriter(tempFile);
124         fw.write(output);
125         fw.close();
126         return;
127     }
128
129     /**
130      * Enters the .charj directory and compiles the .cc and .ci files 
131      * generated from the given filename. The given charmc string 
132      * includes all options to be passed to charmc. Any generated .o 
133      * file is moved back to the initial directory.
134      */
135     private void compileTempFiles(
136             String filename,
137             String charmc) throws
138         IOException, InterruptedException
139     {
140         int lastDot = filename.lastIndexOf(".");
141         int lastSlash = filename.lastIndexOf("/");
142         String baseDirectory = filename.substring(0, lastSlash + 1);
143         if (baseDirectory.equals("")) {
144             baseDirectory = "./";
145         }
146         String tempDirectory = baseDirectory + ".charj/";
147         String moduleName = filename.substring(lastSlash + 1, lastDot);
148         String baseTempFilename = tempDirectory + moduleName;
149
150         // Compile interface file
151         String cmd = charmc + " " + baseTempFilename + ".ci";
152         File currentDir = new File(".");
153         int retVal = exec(cmd, currentDir);
154         if (retVal != 0) {
155             error("Could not compile generated interface file");
156             return;
157         }
158
159         // Move decl.h and def.h into temp directory.
160         // charmxi/charmc doesn't offer control over where to generate these
161         cmd = "mv " + moduleName + ".decl.h " + moduleName + ".def.h " +
162             tempDirectory;
163         retVal = exec(cmd, currentDir);
164          if (retVal != 0) {
165             error("Could not move .decl.h and .def.h files " +
166                     "into temp directory");
167             return;
168         }       
169
170         // Compile c++ output
171         cmd = charmc + " -c " + baseTempFilename + ".cc" + 
172             " -o " + baseTempFilename + ".o";
173         retVal = exec(cmd, currentDir);
174         if (retVal != 0) {
175             error("Could not compile generated C++ file");
176             return;
177         }
178
179         // move generated .o and .h file into .cj directory
180         cmd = "mv -f " + baseTempFilename + ".o " + baseDirectory;
181         exec(cmd, currentDir);
182         cmd = "cp -f " + baseTempFilename + ".h " + baseDirectory;
183         exec(cmd, currentDir);
184     }
185
186     /**
187      * Utility function to execute a given command line.
188      */
189     private int exec(String cmd, File outputDir) throws
190         IOException, InterruptedException
191     {
192         if (m_verbose) System.out.println(" [charjc] exec: " + cmd);
193         Process p = Runtime.getRuntime().exec(cmd, null, outputDir);
194         StreamEmitter stdout = new StreamEmitter(
195                 p.getInputStream(), System.out);
196         StreamEmitter stderr = new StreamEmitter(
197                 p.getErrorStream(), System.err);
198         stdout.start();
199         stderr.start();
200         p.waitFor();
201         stdout.join();
202         stderr.join();
203         int retVal = p.exitValue();
204         return retVal;
205     }
206
207     private String emit(
208             CommonTreeNodeStream nodes, 
209             OutputMode m) throws
210         RecognitionException, IOException, InterruptedException
211     {
212         CharjEmitter emitter = new CharjEmitter(nodes);
213         StringTemplateGroup templates = getTemplates(templateFile);
214         emitter.setTemplateLib(templates);
215         StringTemplate st = (StringTemplate)emitter.charjSource(m).getTemplate();
216         return st.toString();
217     }
218
219     private StringTemplateGroup getTemplates(String templateFile)
220     {
221         StringTemplateGroup templates = null;
222         try {
223             ClassLoader loader = Thread.currentThread().getContextClassLoader();
224             InputStream istream = loader.getResourceAsStream(templateFile);
225             BufferedReader reader = 
226                 new BufferedReader(new InputStreamReader(istream));
227             templates = new StringTemplateGroup(reader);
228             reader.close();
229         } catch(IOException ex) {
230             error("Failed to load template file", ex); 
231         }
232         return templates;
233     }
234
235     public File findPackage(String packageName)
236     {
237         // TODO: implement me
238         // turn package name into a file path
239         // look in: current directory, stdlib, user specified directory
240         return null;
241     }
242
243     /** Load a class from disk looking in lib/package
244      *  Side-effect: add class to symtab.
245      */
246     public ClassSymbol loadType(String packageName, String typeName)
247     {
248         // TODO: implement me
249         return null;
250     }
251     
252     private void error(
253             String sourceName, 
254             String msg, 
255             CommonTree node) 
256     {
257         m_errorCondition = true;
258         String linecol = ":";
259         if ( node!=null ) {
260             CommonToken t = (CommonToken)node.getToken();
261             linecol = ": line " + t.getLine() + ":" + t.getCharPositionInLine();
262         }
263         System.err.println(sourceName + linecol + " " + msg);
264         System.err.flush();
265     }
266
267
268     private void error(
269             String sourceName, 
270             String msg) {
271         error(sourceName, msg, (CommonTree)null);
272     }
273
274
275     public void error(String msg) {
276         error(" [charjc] error", msg, (CommonTree)null);
277     }
278
279
280     public void error(
281             String msg, 
282             Exception e) {
283         error(msg);
284         e.printStackTrace(System.err);
285     }
286 }