1 | package PIANOS.io; |
2 | |
3 | import java.io.*; |
4 | |
5 | import java.util.ArrayList; |
6 | import java.util.regex.*; |
7 | |
8 | /** |
9 | * FortranWriter, a class that receives lines of Fortran code, multilines and indents them correctly and writes them to a file. |
10 | */ |
11 | public class FortranWriter { |
12 | |
13 | private static final String[] BEGIN_INDENT = {"BLOCK\\p{Space}*DATA", "DO", "FORALL", |
14 | "FUNCTION", "IF", "INTERFACE", "MODULE", "TYPE\\p{Space}*[.[^\\(]]+", "PROGRAM", |
15 | "SELECT", "SUBROUTINE", "CASE\\p{Space}*\\(", "WHERE", "CONTAINS", "ELSE", "ELSEWHERE"}; |
16 | |
17 | private static final String[] END_INDENT = {"END", "CASE\\p{Space}*\\(", "CONTAINS", "ELSE", "ELSEWHERE"}; |
18 | |
19 | private static final int INDENT_CHARS = 4; |
20 | private static final int MAX_LINE_LENGTH = 79; |
21 | |
22 | private File file; |
23 | private int indent; |
24 | private boolean first_write = true; |
25 | |
26 | /** |
27 | * Creates a new <code>FortranWriter</code>. |
28 | * |
29 | * @param fileName name of the file the Fortran source code will be |
30 | * written to |
31 | */ |
32 | public FortranWriter(String fileName) { |
33 | file = new File(fileName); |
34 | indent = 0; |
35 | } |
36 | |
37 | /* |
38 | //Considered obsolete and slow |
39 | //Call write(ArrayList<String>) or write(String[]) |
40 | //so that the file is not closed and opened every time |
41 | |
42 | public void write(String line) throws IOException { |
43 | String[] array = new String[1]; |
44 | array[1] = line; |
45 | this.write(array); |
46 | } |
47 | */ |
48 | /** |
49 | * Writes lines of Fortran source code into the file. |
50 | * |
51 | * @param lines an ArrayList containing the lines to be written to the |
52 | * file |
53 | * |
54 | * @throws IOException If the file couldn't be written to |
55 | */ |
56 | |
57 | public void write(ArrayList<String> lines) throws IOException{ |
58 | write(lines.toArray(new String[lines.size()])); |
59 | } |
60 | |
61 | /** |
62 | * Writes lines of Fortran source code into the file. |
63 | * |
64 | * @param lines an array containing the lines to be written to the |
65 | * file |
66 | * |
67 | * @throws IOException If the file couldn't be written to |
68 | */ |
69 | public void write(String[] lines) throws IOException { |
70 | FileWriter out; |
71 | if (first_write) { |
72 | out = new FileWriter(file, false); |
73 | first_write = false; |
74 | } else out = new FileWriter(file, true); |
75 | |
76 | for (int j = 0; j < lines.length; j++){ |
77 | String line = lines[j].trim(); |
78 | |
79 | if (line.length() <= 0){ |
80 | out.write(getIndent() + line + "\n"); |
81 | continue; |
82 | } |
83 | if (line.charAt(0) == '!'){ |
84 | out.write(getIndent() + line + "\n"); |
85 | continue; |
86 | } |
87 | |
88 | for (int i = 0; i < END_INDENT.length; i++) |
89 | if (line.matches("^\\p{Space}*" + END_INDENT[i] + ".*$")) |
90 | indent = indent - INDENT_CHARS; |
91 | |
92 | String loopline = line; // we must save the original line. |
93 | |
94 | if (indent + loopline.length() > MAX_LINE_LENGTH) { |
95 | boolean firstLine = true; |
96 | boolean characterContinue = false; |
97 | String temp = loopline; |
98 | while (temp != null){ |
99 | if (indent + temp.length() > MAX_LINE_LENGTH) { |
100 | if (!firstLine) |
101 | indent = indent + INDENT_CHARS; |
102 | |
103 | int indentedMax = MAX_LINE_LENGTH -indent; |
104 | |
105 | //int last_space = temp.lastIndexOf(" ", MAX_LINE_LENGTH - 2); |
106 | int last_space = temp.lastIndexOf(" ", indentedMax - 2); |
107 | if (last_space == -1){ |
108 | last_space = temp.lastIndexOf(" "); |
109 | if (last_space == -1){ |
110 | System.out.println("In "+ file + ": Please cut the line \"" +line + "\" manually " + |
111 | "if You have problems compiling the program. " + |
112 | "I can't see how to cut it properly"); |
113 | break; // if we can't cut it let's leave it and hope |
114 | } |
115 | } |
116 | |
117 | out.write(getIndent() + temp.substring(0, last_space) + " &\n"); |
118 | // PROBLEM. MESSES UP CHARACTER STRINGS. |
119 | // FIX. regex for character strings in Fortran: |
120 | // '[.[^']]*' |
121 | // This is assuming that '' is not used, and " are not used. |
122 | // check if last_space is inside a matching section. |
123 | Pattern p = Pattern.compile("'[.[^']]*'"); |
124 | Pattern cl = Pattern.compile("^\\&[.[^']]*'"); |
125 | Matcher ch = cl.matcher(temp); |
126 | Matcher m = p.matcher(temp); |
127 | boolean matched = false; |
128 | while (m.find()){ |
129 | String characters = m.group(); |
130 | if (m.start() <= last_space && last_space < m.end()){ |
131 | // it's inside. We need a & after last_space. |
132 | temp = temp.substring(0, last_space + 1) + "&" + temp.substring(last_space +1); |
133 | matched = true; |
134 | } |
135 | } |
136 | if (!matched){ |
137 | while (ch.find()){ |
138 | String characters = ch.group(); |
139 | if (ch.start() <= last_space && last_space < ch.end()){ |
140 | // it's inside. We need a & after last_space. |
141 | temp = temp.substring(0, last_space + 1) + "&" + temp.substring(last_space +1); |
142 | } |
143 | |
144 | } |
145 | } |
146 | // we did not skew index numbering, hopefully. |
147 | loopline = temp.substring(last_space + 1); |
148 | temp = loopline; |
149 | |
150 | if (!firstLine) |
151 | indent = indent - INDENT_CHARS; |
152 | else firstLine = false; |
153 | } else { |
154 | indent = indent + INDENT_CHARS; |
155 | out.write(getIndent() + temp + "\n"); |
156 | indent = indent - INDENT_CHARS; |
157 | // also indent the last continual line |
158 | temp = null; |
159 | // only after THAT terminate the loop. |
160 | /* in Anni's version the last continual line was |
161 | * mistakenly lost. |
162 | */ |
163 | } |
164 | |
165 | } |
166 | } else out.write(getIndent() + line + "\n"); |
167 | |
168 | |
169 | for (int i = 0; i < BEGIN_INDENT.length; i++){ |
170 | if (line.matches("^\\p{Space}*" + BEGIN_INDENT[i] + ".*$")){ |
171 | if (!line.matches("^\\p{Space}*END.*$") && |
172 | !line.matches("^\\p{Space}*MODULE\\p{Space}+PROCEDURE\\p{Space}+.*$") && |
173 | !line.matches("^\\p{Space}*MODULE\\p{Space}+procedure\\p{Space}+.*$")) { |
174 | indent = indent + INDENT_CHARS; |
175 | } |
176 | } |
177 | } |
178 | } |
179 | out.close(); |
180 | } |
181 | |
182 | private String getIndent() { |
183 | String spaces = ""; |
184 | for (int i = 0; i < indent; i++) { |
185 | spaces = spaces + " "; |
186 | } |
187 | return spaces; |
188 | } |
189 | |
190 | } |