xref: /reactos/sdk/tools/ms2ps/ms2ps.cpp (revision 8a978a17)
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 
58 int isident( int c ) {
59     return (c != '{') && (c != '}') && (c != '(') && (c != ')') &&
60            (c != '\'') && (c != '\"') && !isspace(c);
61 }
62 
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 
72 bool areident( string s ) { return areinclass( s, isident ); }
73 
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 
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 
88 string match_operator( string tok, string la ) {
89     return generic_match( tok, la, isop );
90 }
91 
92 string match_ident( string tok, string la ) {
93     return generic_match( tok, la, areident );
94 }
95 
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 
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 
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 
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
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 
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 
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 
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 
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 
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 
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