/* $Id$ * $Log$ * Revision 1.4 2002/05/01 12:54:55 geraint * Now recognises keywords terminated with ; as well as ws. * Now recognises # as a comment when not terminated by ws. * i.e. CarnotCycle_input.txt now gets translated correctly! * * Revision 1.3 2001/07/13 04:54:04 geraint * Branch merge: numerical-algebraic-solution back to main. * * Revision 1.2.2.1 2001/06/30 03:26:17 geraint * gcc-3.0 compatibility. * * Revision 1.2 2001/03/19 02:28:53 geraint * Branch merge: merging-ode2odes-exe back to MAIN. * * Revision 1.1.2.2 2001/03/09 04:01:20 geraint * \ escapes newline. * * Revision 1.1.2.1 2001/03/09 02:59:26 geraint * got_comment: (char)c no longer compared to (int)EOF. * * Revision 1.1 2000/12/28 09:46:05 peterg * put under RCS * * Revision 1.1 2000/10/31 04:29:50 geraint * Initial revision * */ #include <cstdio> #include <cstdlib> #include <iostream> #include <map> #include <stack> #include <string> /* * Bracket.hh deals with nesting levels of parenthesis * just add Bracket pointer to string / stream */ #include "Bracket.hh" using namespace std; /* * use lbrace, etc. in expressions to automate nesting calculations */ LeftBrace *lbrace = new LeftBrace; RightBrace *rbrace = new RightBrace; LeftParen *lparen = new LeftParen; RightParen *rparen = new RightParen; /* * use brace nesting depth to determine indentation */ string indent (void) { return lbrace->indentation (); } /* * map contains keyword to look for and function to call when found */ map <string, void (*)(void)> keyword; /* * stack records current nest type * so that "end" can be handled correctly */ enum nest_type { null, if_statement, switch_statement, while_statement }; stack <enum nest_type> current_nest; /* * assuming cin has '(' as next character * find the matching ')' and return the string contained within */ string get_test (void) { const int entry_nesting = lparen->get_nesting_depth (); char c; string buf = ""; cin.setf (ios::skipws); cin >> c; if ('(' != c) { cerr << "Sorry, test must be enclosed in ( )" << endl; cerr << "current character is " << c << endl; /* * replace this with a call to get_expression maybe? */ exit (-1); } else { buf += lparen; } cin.unsetf (ios::skipws); while (entry_nesting != lparen->get_nesting_depth ()) { cin >> c; switch (c) { case '(': buf += lparen; break; case ')': buf += rparen; break; case EOF: cerr << "Oops! EOF reached" << endl; exit (-1); default: buf += c; break; } } return buf; } /* * functions to be called upon detection of keyword */ void got_if (void) { current_nest.push (if_statement); cout << "if "; cout << get_test (); cout << lbrace; } void got_else (void) { cout << rbrace; cout << "else"; cout << lbrace; } void got_elseif (void) { cout << rbrace; got_if (); } void got_switch (void) { current_nest.push (switch_statement); cout << "switch "; cout << get_test (); cout << lbrace; /* * open a second brace so that each "case" can be enclosed */ cout << lbrace; } void got_case (void) { cout << rbrace; cout << "case "; cout << get_test (); cout << ':'; cout << lbrace; } void got_otherwise (void) { cout << rbrace; cout << "default:"; cout << lbrace; } void got_while (void) { current_nest.push (while_statement); cout << "while "; cout << get_test (); cout << lbrace; } void got_end (void) { enum nest_type n = current_nest.top (); switch (n) { case if_statement: case while_statement: cout << rbrace; break; case switch_statement: cout << rbrace << rbrace; break; default: cerr << "Oops! Unmatched end ... aborting" << endl; exit (-1); break; } current_nest.pop (); } void got_comment (void) { /* * get remainder of line in case there are any commented keywords */ char c; cout << " // "; cin >> c; do { cout << c; } while (c != '\n' && cin >> c); cout << endl << indent () << ';' << endl << indent (); } /* * map contains keyword to look for and functions to call when found * functions must be of the form "void f (void) {...;}" * new structures should also be added to enum nest_type */ void set_keyword (void) { // if keyword ["if"] = got_if; keyword ["else"] = got_else; keyword ["elseif"] = got_elseif; keyword ["endif"] = got_end; // switch keyword ["switch"] = got_switch; keyword ["case"] = got_case; keyword ["otherwise"] = got_otherwise; keyword ["endswitch"] = got_end; // while keyword ["while"] = got_while; keyword ["endwhile"] = got_end; // general keyword ["end"] = got_end; /* * this won't work inside a string * or if there is no space around the delimiter */ keyword ["#"] = got_comment; keyword ["//"] = got_comment; /* * unimplemented keywords * keyword ["for"] = got_for; keyword ["endfor"] = got_end; keyword ["break"] = got_break; keyword ["continue"] = got_continue; */ } /* read in one character at a time looking for tokens (delimited by whitespace) * if the token is a keyword, call the appropriate function */ int main (void) { set_keyword (); string buf = ""; char c; cin.unsetf (ios::skipws); while (cin >> c) { switch (c) { case EOF: return 0; case ' ': case '\t': if (keyword [buf]) { keyword [buf](); } else { if (! lbrace->get_nesting_depth ()) { buf += c; } cout << buf; } buf = ""; break; case ';': case '\n': if (keyword [buf]) { /* * keyword found, call function */ keyword [buf] (); } else { cout << buf /* * keep newline in case this line has an EOL-comment */ << endl /* * EOL is end-of-statement in Octave, add ; */ << indent () << ';' << endl << indent (); } buf = ""; break; case '#': if (keyword [buf]) { /* * keyword found, call function */ keyword [buf] (); } else { cout << buf /* * keep newline in case this line has an EOL-comment */ << endl /* * EOL is end-of-statement in Octave, add ; */ << indent () << ';' << endl << indent (); } keyword ["#"] (); buf = ""; break; case '\\': cin >> c; if ('\n' == c) { buf += '\n'; } else { buf += '\\'; buf += c; } break; default: buf += c; } if (lbrace->get_nesting_depth ()) { cout.setf (ios::skipws); } else { cout.unsetf (ios::skipws); } } return 0; }