1 /*
2 * ReactOS kernel
3 * Copyright (C) 2004 ReactOS Team
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19 /*
20 * COPYRIGHT: See COPYING in the top level directory
21 * PROJECT: ReactOS seh conversion tool
22 * FILE: tools/ms2ps/ms2ps.cpp
23 * PURPOSE: Conversion tool from msvc to pseh style seh
24 * PROGRAMMER: Art Yerkes
25 */
26
27 #include <iostream>
28 #include <vector>
29 #include <list>
30 #include <set>
31 #include <map>
32 #include <deque>
33 #include <ctype.h>
34
35 #define MAYBE(x)
36
37 using std::string;
38 using std::cin;
39 using std::cout;
40 using std::cerr;
41 using std::endl;
42 using std::istream;
43
44 typedef std::list<std::string> sl_t;
45 typedef sl_t::iterator sl_it;
46
47 string TRY_TOKEN = "__try";
48 string EXCEPT_TOKEN = "__except";
49 string FINALLY_TOKEN = "__finally";
50 char *c_operators[] = {
51 "{",
52 "}",
53 "(",
54 ")",
55 NULL
56 };
57
isident(int c)58 int isident( int c ) {
59 return (c != '{') && (c != '}') && (c != '(') && (c != ')') &&
60 (c != '\'') && (c != '\"') && !isspace(c);
61 }
62
areinclass(string str,int (* isclass)(int))63 bool areinclass( string str, int (*isclass)(int) ) {
64 int i;
65
66 for( i = 0; i < (int)str.size(); i++ )
67 if( !isclass( str[i] ) ) return false;
68
69 return true;
70 }
71
areident(string s)72 bool areident( string s ) { return areinclass( s, isident ); }
73
isop(string tok)74 bool isop( string tok ) {
75 int i;
76 for( i = 0; c_operators[i] && tok != c_operators[i]; i++ );
77 if( c_operators[i] ) return true; else return false;
78 }
79
80 enum fstate { EMPTY, INT, FRAC, EXP };
81
generic_match(string tok,string la,bool (* mf)(string))82 string generic_match( string tok, string la,
83 bool (*mf)( string ) ) {
84 if( tok.size() < 1 ) return "";
85 if( mf(tok) && !mf(la) ) return tok; else return "";
86 }
87
match_operator(string tok,string la)88 string match_operator( string tok, string la ) {
89 return generic_match( tok, la, isop );
90 }
91
match_ident(string tok,string la)92 string match_ident( string tok, string la ) {
93 return generic_match( tok, la, areident );
94 }
95
match_quoted_const(string tok,string la,char q)96 string match_quoted_const( string tok, string la, char q ) {
97 if( ((tok.size() && tok[0] == q) ||
98 ((tok.size() > 2) && tok[0] == 'L' && tok[1] == q)) &&
99 (tok.rfind(q) == (tok.size() - 1)) ) {
100 if( (tok.rfind("\\") != (tok.size() - 2)) ||
101 (tok.size() > 3 && tok.rfind("\\\\") == (tok.size() - 3)) )
102 return tok;
103 else return "";
104 }
105 else return "";
106 }
107
snarf_tokens(string line)108 sl_t snarf_tokens( string line ) {
109 int i;
110 sl_t out;
111 string curtok, la, op, ident, qconst;
112
113 line += " ";
114
115 for( i = 0; i < (int)line.size() - 1; i++ ) {
116 /*cout << "Char [" << line[i] << "] and [" << line[i+1] << "]"
117 << endl; */
118
119 if( (!curtok.size() ||
120 (curtok[0] != '\'' && curtok[0] != '\"')) &&
121 (curtok.size() <= 2 ||
122 curtok[0] != 'L' ||
123 (curtok[1] != '\'' && curtok[1] != '\"')) &&
124 isspace(line[i]) ) {
125 if( curtok.size() ) out.push_back( curtok );
126 curtok = "";
127 continue;
128 }
129
130 curtok.push_back( line[i] );
131
132 la = curtok + line[i+1];
133
134 op = match_operator( curtok, la );
135
136 if( op != "" ) {
137 out.push_back( op MAYBE(+ "O") );
138 curtok = "";
139 continue;
140 }
141
142 if( la != "L\"" && la != "L\'" ) {
143 ident = match_ident( curtok, la );
144
145 if( ident != "" ) {
146 out.push_back( ident MAYBE(+ "I") );
147 curtok = "";
148 continue;
149 }
150 }
151
152 qconst = match_quoted_const( curtok, la, '\'' );
153
154 if( qconst != "" ) {
155 out.push_back( qconst MAYBE(+ "q") );
156 curtok = "";
157 continue;
158 }
159
160 qconst = match_quoted_const( curtok, la, '\"' );
161
162 if( qconst != "" ) {
163 out.push_back( qconst MAYBE(+ "Q") );
164 curtok = "";
165 continue;
166 }
167 }
168
169 return out;
170 }
171
getline_no_comments(istream & is,string & line)172 istream &getline_no_comments( istream &is, string &line ) {
173 string buf;
174 int ch;
175 int seen_slash = false;
176
177 while( (ch = is.get()) != -1 ) {
178 if( seen_slash ) {
179 if( ch == '/' ) {
180 do {
181 ch = is.get();
182 } while( ch != -1 && ch != '\n' && ch != '\r' );
183 break;
184 } else if( ch == '*' ) {
185 ch = is.get(); /* Skip one char */
186 do {
187 while( ch != '*' )
188 ch = is.get();
189 ch = is.get();
190 } while( ch != '/' );
191 buf += ' ';
192 } else {
193 buf += '/'; buf += (char)ch;
194 }
195 seen_slash = false;
196 } else {
197 if( ch == '/' ) seen_slash = true;
198 else if( ch == '\r' || ch == '\n' ) break;
199 else buf += (char)ch;
200 }
201 }
202
203 line = buf;
204
205 return is;
206 }
207
expand_input(sl_t & tok)208 bool expand_input( sl_t &tok ) {
209 string line;
210 sl_t new_tokens;
211 bool out = false;
212
213 out = getline_no_comments( cin, line );
214 while( line.size() && isspace( line[0] ) )
215 line = line.substr( 1 );
216 if( line[0] == '#' ) {
217 tok.push_back( line );
218 while( line[line.size()-1] == '\\' ) {
219 getline_no_comments( cin, line );
220 tok.push_back( line );
221 tok.push_back( "\n" );
222 }
223 tok.push_back( "\n" );
224 } else {
225 new_tokens = snarf_tokens( line );
226 tok.splice( tok.end(), new_tokens );
227 tok.push_back( "\n" );
228 }
229
230 return out;
231 }
232
233 sl_it
complete_block(sl_it i,sl_it end,string start_ch,string end_ch)234 complete_block( sl_it i,
235 sl_it end,
236 string start_ch,
237 string end_ch) {
238 int bc = 1;
239
240 for( i++; i != end && bc; i++ ) {
241 if( *i == start_ch ) bc++;
242 if( *i == end_ch ) bc--;
243 }
244
245 return i;
246 }
247
makename(string intro)248 string makename( string intro ) {
249 static int i = 0;
250 char buf[100];
251
252 sprintf( buf, "%s%d", intro.c_str(), i++ );
253
254 return buf;
255 }
256
append_block(sl_t & t,sl_it b,sl_it e)257 void append_block( sl_t &t, sl_it b, sl_it e ) {
258 while( b != e ) {
259 t.push_back( *b );
260 b++;
261 }
262 }
263
error(sl_t & container,sl_it it,string l)264 void error( sl_t &container, sl_it it, string l ) {
265 int line = 0;
266 for( sl_it i = container.begin(); i != it; i++ )
267 if( (*i)[0] == '#' ) {
268 sscanf( i->substr(1).c_str(), "%d", &line );
269 cerr << "*standard-input*:" << line << ": " << l;
270 }
271 }
272
273 /* Goal: match and transform one __try { a } __except [ (foo) ] { b }
274 * [ __finally { c } ]
275 *
276 * into
277 *
278 * _SEH_FINALLY(name1) { c }
279 * _SEH_FILTER(name2) { return (foo | EXCEPTION_EXECUTE_HANDLER); }
280 * _SEH_TRY_FILTER_FINALLY(name1,name2) {
281 * a
282 * } _SEH_HANDLE {
283 * b
284 * } _SEH_END;
285 */
286
handle_try(sl_t & container,sl_it try_kw,sl_it end)287 void handle_try( sl_t &container, sl_it try_kw, sl_it end ) {
288 string temp;
289 sl_t pseh_clause, temp_tok;
290 string finally_name, filter_name;
291 sl_it try_block, try_block_end, except_kw, paren, end_paren,
292 except_block, except_block_end, todelete,
293 finally_kw, finally_block, finally_block_end, clause_end;
294
295 try_block = try_kw;
296 try_block++;
297 try_block_end = complete_block( try_block, end, "{", "}" );
298
299 if( try_block_end == end )
300 error( container, try_block, "unclosed try block");
301
302 except_kw = try_block_end;
303
304 if( *except_kw == FINALLY_TOKEN ) {
305 finally_kw = except_kw;
306 except_kw = end;
307 paren = end;
308 end_paren = end;
309 except_block = end;
310 except_block_end = end;
311 } else if( *except_kw == EXCEPT_TOKEN ) {
312 paren = except_kw;
313 paren++;
314 if( *paren == "(" ) {
315 end_paren = complete_block( paren, end, "(", ")" );
316 except_block = end_paren;
317 } else {
318 except_block = paren;
319 paren = end;
320 end_paren = end;
321 }
322 except_block_end = complete_block( except_block, end, "{", "}" );
323 finally_kw = except_block_end;
324 } else {
325 except_kw = paren = end_paren = except_block = except_block_end =
326 finally_kw = finally_block = finally_block_end = end;
327 }
328
329 if( finally_kw != end && *finally_kw != FINALLY_TOKEN ) {
330 finally_kw = end;
331 finally_block = end;
332 finally_block_end = end;
333 } else {
334 finally_block = finally_kw;
335 finally_block++;
336 finally_block_end = complete_block( finally_block, end, "{", "}" );
337 }
338
339 if( finally_block_end != end ) clause_end = finally_block_end;
340 else if( except_block_end != end ) clause_end = except_block_end;
341 else clause_end = try_block_end;
342
343 /* Skip one so that we can do != on clause_end */
344
345 /* Now for the output phase -- we've collected the whole seh clause
346 * and it lies between try_kw and clause_end */
347
348 finally_name = makename("_Finally");
349 filter_name = makename("_Filter");
350
351 pseh_clause.push_back( "_SEH_FINALLY" );
352 pseh_clause.push_back( "(" );
353 pseh_clause.push_back( finally_name );
354 pseh_clause.push_back( ")" );
355 if( finally_kw != end )
356 append_block( pseh_clause, finally_block, finally_block_end );
357 else {
358 pseh_clause.push_back( "{" );
359 pseh_clause.push_back( "}" );
360 }
361
362 pseh_clause.push_back( "_SEH_FILTER" );
363 pseh_clause.push_back( "(" );
364 pseh_clause.push_back( filter_name );
365 pseh_clause.push_back( ")" );
366 pseh_clause.push_back( "{" );
367 pseh_clause.push_back( "return" );
368 if( paren != end )
369 append_block( pseh_clause, paren, end_paren );
370 else
371 pseh_clause.push_back( "EXCEPTION_EXECUTE_HANDLER" );
372 pseh_clause.push_back( ";" );
373 pseh_clause.push_back( "}" );
374
375 pseh_clause.push_back( "_SEH_TRY_FILTER_FINALLY" );
376 pseh_clause.push_back( "(" );
377 pseh_clause.push_back( filter_name );
378 pseh_clause.push_back( "," );
379 pseh_clause.push_back( finally_name );
380 pseh_clause.push_back( ")" );
381 append_block( pseh_clause, try_block, try_block_end );
382 pseh_clause.push_back( "_SEH_HANDLE" );
383 pseh_clause.push_back( "{" );
384 if( except_block != end )
385 append_block( pseh_clause, except_block, except_block_end );
386 pseh_clause.push_back( "}" );
387 pseh_clause.push_back( "_SEH_END" );
388 pseh_clause.push_back( ";" );
389
390 container.splice( try_kw, pseh_clause );
391 while( try_kw != clause_end ) {
392 todelete = try_kw;
393 try_kw++;
394 container.erase( todelete );
395 }
396 }
397
print_tokens(sl_it begin,sl_it end)398 void print_tokens( sl_it begin, sl_it end ) {
399 for( sl_it i = begin; i != end; i++ )
400 if( *i == "\n" ) cout << *i;
401 else cout << /*"[" <<*/ *i << /*"]" <<*/ " ";
402 }
403
main(int argc,char ** argv)404 int main( int argc, char **argv ) {
405 sl_t tok;
406 sl_it try_found;
407 int i;
408
409 for( i = 1; i < argc; i++ ) {
410 if( string(argv[i]) == "-try" && i < argc - 1 ) {
411 i++;
412 TRY_TOKEN = argv[i];
413 } else if( string(argv[i]) == "-except" && i < argc - 1 ) {
414 i++;
415 EXCEPT_TOKEN = argv[i];
416 } else if( string(argv[i]) == "-finally" && i < argc - 1 ) {
417 i++;
418 FINALLY_TOKEN = argv[i];
419 }
420 }
421
422 /* XXX Uses much memory for large files */
423 while( expand_input(tok) );
424
425 while( (try_found = find( tok.begin(), tok.end(), TRY_TOKEN )) !=
426 tok.end() ) {
427 handle_try( tok, try_found, tok.end() );
428 }
429
430 tok.push_front("#include <pseh/framebased.h>\n");
431 print_tokens( tok.begin(), tok.end() );
432 }
433