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