ucstmt.cc

Go to the documentation of this file.
00001 
00007 /*
00008 Copyright (C) 2000 The Exult Team
00009 
00010 This program is free software; you can redistribute it and/or
00011 modify it under the terms of the GNU General Public License
00012 as published by the Free Software Foundation; either version 2
00013 of the License, or (at your option) any later version.
00014 
00015 This program is distributed in the hope that it will be useful,
00016 but WITHOUT ANY WARRANTY; without even the implied warranty of
00017 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00018 GNU General Public License for more details.
00019 
00020 You should have received a copy of the GNU General Public License
00021 along with this program; if not, write to the Free Software
00022 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
00023 */
00024 
00025 #ifdef HAVE_CONFIG_H
00026 #  include <config.h>
00027 #endif
00028 
00029 #include <stdio.h>
00030 #include "ucstmt.h"
00031 #include "ucexpr.h"
00032 #include "ucsym.h"
00033 #include "opcodes.h"
00034 #include "utils.h"
00035 #include "ucfun.h"
00036 
00037 using std::vector;
00038 using std::string;
00039 
00040 int Uc_converse2_statement::nest = 0;
00041 
00042 /*
00043  *  Delete.
00044  */
00045 
00046 Uc_block_statement::~Uc_block_statement
00047   (
00048   )
00049   {
00050           // Delete all the statements.
00051   for (std::vector<Uc_statement *>::const_iterator it = statements.begin();
00052           it != statements.end(); it++)
00053     delete (*it);
00054   }
00055 
00056 /*
00057  *  Generate code.
00058  */
00059 
00060 void Uc_block_statement::gen
00061   (
00062   vector<char>& out,
00063   Uc_function *fun
00064   )
00065   {
00066   for (std::vector<Uc_statement *>::const_iterator it = statements.begin();
00067           it != statements.end(); it++)
00068     {
00069     Uc_statement *stmt = *it;
00070     stmt->gen(out, fun);
00071     }
00072   }
00073 
00074 
00075 /*
00076  *  Delete.
00077  */
00078 
00079 Uc_assignment_statement::~Uc_assignment_statement
00080   (
00081   )
00082   {
00083   delete target;
00084   delete value;
00085   }
00086 
00087 
00088 /*
00089  *  Generate code.
00090  */
00091 
00092 void Uc_assignment_statement::gen
00093   (
00094   vector<char>& out,
00095   Uc_function * /* fun */
00096   )
00097   {
00098   value->gen_value(out);    // Get value on stack.
00099   target->gen_assign(out);
00100   }
00101 
00102 /*
00103  *  Generate code.
00104  */
00105 
00106 void Uc_if_statement::gen
00107   (
00108   vector<char>& out,
00109   Uc_function *fun
00110   )
00111   {
00112           // Gen JNE (or CMPS) past IF code.
00113   int jne_offset = expr->gen_jmp_if_false(out, 0);
00114   if (if_stmt)
00115     if_stmt->gen(out, fun);
00116   int jmp_past_else_offset = -1;  // Where following JMP offset is.
00117   if (else_stmt)      // JMP past ELSE code.
00118     {
00119     out.push_back((char) UC_JMP);
00120     jmp_past_else_offset = out.size();
00121     Write2(out, 0);   // Write place-holder for offset.
00122     }
00123   int if_end = out.size();
00124           // Fixup JNE at start.
00125   Write2(out, jne_offset, if_end - (jne_offset + 2));
00126   if (else_stmt)      // Generate ELSE.
00127     {
00128     else_stmt->gen(out, fun);
00129     int else_end = out.size();
00130     Write2(out, jmp_past_else_offset,
00131           else_end - (jmp_past_else_offset + 2));
00132     }
00133   }
00134 
00135 /*
00136  *  Delete.
00137  */
00138 
00139 Uc_if_statement::~Uc_if_statement
00140   (
00141   )
00142   {
00143   delete expr;
00144   delete if_stmt;
00145   delete else_stmt;
00146   }
00147 
00148 /*
00149  *  Delete.
00150  */
00151 
00152 Uc_while_statement::~Uc_while_statement
00153   (
00154   )
00155   {
00156   delete expr;
00157   delete stmt;
00158   }
00159 
00160 /*
00161  *  Generate code.
00162  */
00163 
00164 void Uc_while_statement::gen
00165   (
00166   vector<char>& out,
00167   Uc_function *fun
00168   )
00169   {
00170   int top = out.size();   // Get current position.
00171   expr->gen_value(out);   // Generate expr. value.
00172   vector<char> stmt_code;
00173   stmt_code.reserve(4000);
00174   fun->start_breakable(this);
00175   if (stmt) {
00176     fun->adjust_reloffset(out.size() + 3);
00177     stmt->gen(stmt_code, fun);  // Generate statement's code.
00178     fun->adjust_reloffset(-out.size() - 3);
00179   }
00180   int stmtlen = stmt_code.size();
00181           // Get distance back to top, including
00182           //   a JNE and a JMP.
00183   long dist = stmtlen + (out.size() - top) + 3 + 3;
00184           // Generate JMP back to top.
00185   stmt_code.push_back((char) UC_JMP);
00186   Write2(stmt_code, -dist);
00187   stmtlen = stmt_code.size(); // Get total length.
00188   fun->end_breakable(this, stmt_code);
00189   out.push_back((char) UC_JNE); // Put cond. jmp. after test.
00190   Write2(out, stmtlen);   // Skip around body if false.
00191 //  out.append(stmt_code);
00192           // Append code to end.
00193   out.insert(out.end(), stmt_code.begin(), stmt_code.end());
00194   }
00195 
00196 /*
00197  *  Delete.
00198  */
00199 
00200 Uc_arrayloop_statement::~Uc_arrayloop_statement
00201   (
00202   )
00203   {
00204   delete stmt;
00205   }
00206 
00207 /*
00208  *  Finish up creation.
00209  */
00210 
00211 void Uc_arrayloop_statement::finish
00212   (
00213   Uc_function *fun
00214   )
00215   {
00216   char buf[100];
00217   if (!index)     // Create vars. if not given.
00218     {
00219     sprintf(buf, "_%s_index", array->get_name());
00220     index = fun->add_symbol(buf);
00221     }
00222   if (!array_size);
00223     {
00224     sprintf(buf, "_%s_size", array->get_name());
00225     array_size = fun->add_symbol(buf);
00226     }
00227   }
00228 
00229 /*
00230  *  Generate code.
00231  */
00232 
00233 void Uc_arrayloop_statement::gen
00234   (
00235   vector<char>& out,
00236   Uc_function *fun
00237   )
00238   {
00239   if (!stmt)
00240     return;     // Nothing useful to do.
00241   out.push_back((char) UC_LOOP);  // Start of loop.
00242   int top = out.size();   // This is where to jump back to.
00243   out.push_back((char) UC_LOOPTOP);
00244   Write2(out, index->get_offset());// Counter, total-count variables.
00245   Write2(out, array_size->get_offset());
00246   Write2(out, var->get_offset()); // Loop variable, than array.
00247   Write2(out, array->get_offset());
00248           // Still need to write offset to end.
00249   int testlen = out.size() + 2 - top;
00250   vector<char> stmt_code;
00251   stmt_code.reserve(4000);
00252   fun->start_breakable(this);
00253   fun->adjust_reloffset(out.size() + 2);
00254   stmt->gen(stmt_code, fun);  // Generate statement's code.
00255   fun->adjust_reloffset(-out.size() - 2);
00256           // Back to top includes JMP at end.
00257   int dist = testlen + stmt_code.size() + 3;
00258   stmt_code.push_back((char) UC_JMP); // Generate JMP back to top.
00259   Write2(stmt_code, -dist);
00260   int stmtlen = stmt_code.size(); // Get total length.
00261   Write2(out, stmtlen);   // Finally, offset past loop stmt.
00262   fun->end_breakable(this, stmt_code);
00263           // Write out body.
00264   out.insert(out.end(), stmt_code.begin(), stmt_code.end());
00265   }
00266 
00267 /*
00268  *  Delete.
00269  */
00270 
00271 Uc_return_statement::~Uc_return_statement
00272   (
00273   )
00274   {
00275   delete expr;
00276   }
00277 
00278 /*
00279  *  Generate code.
00280  */
00281 
00282 void Uc_return_statement::gen
00283   (
00284   vector<char>& out,
00285   Uc_function *fun
00286   )
00287   {
00288   if (expr)     // Returning something?
00289     {
00290     expr->gen_value(out); // Put value on stack.
00291     out.push_back((char) UC_SETR);// Pop into ret_value.
00292     out.push_back((char) UC_RTS);
00293     }
00294   else
00295     out.push_back((char) UC_RET);
00296   }
00297 
00298 
00299 /*
00300  *  Generate code.
00301  */
00302 
00303 void Uc_break_statement::gen
00304   (
00305   vector<char>& out,
00306   Uc_function *fun
00307   )
00308   {
00309           // Store our location.
00310   fun->add_break(out.size()); //+++++if in an IF???
00311   out.push_back((char) UC_JMP);
00312   Write2(out, 0);     // To be filled in at end of loop.
00313   }
00314 
00315 
00316 void Uc_label_statement::gen
00317   (
00318   vector<char>& out,
00319   Uc_function *fun
00320   )
00321 {
00322   // use reloffset to compensate for jumps to points in separately
00323   // generated blocks of code
00324   label->set_offset(out.size() + fun->get_reloffset());
00325 
00326   // no code
00327 }
00328 
00329 
00330 void Uc_goto_statement::gen
00331   (
00332   vector<char>& out,
00333   Uc_function *fun
00334   )
00335 {
00336   Uc_label *l = fun->search_label(label);
00337   if (l) {
00338     // use reloffset to compensate for jumps to points in separately
00339     // generated blocks of code
00340     l->add_reference(out.size() + fun->get_reloffset());
00341     out.push_back((char) UC_JMP);
00342     Write2(out, 0); // will be filled in later
00343   } else {
00344     char buf[255];
00345     snprintf(buf, 255, "Undeclared label: '%s'", label);
00346     error(buf);
00347   }
00348 }
00349 
00350 /*
00351  *  Delete.
00352  */
00353 
00354 Uc_converse_statement::~Uc_converse_statement
00355   (
00356   )
00357   {
00358   delete stmt;
00359   }
00360 
00361 /*
00362  *  Generate code.
00363  */
00364 
00365 void Uc_converse_statement::gen
00366   (
00367   vector<char>& out,
00368   Uc_function *fun
00369   )
00370   {
00371   long top = out.size();    // Get current position.
00372   vector<char> stmt_code;
00373   fun->start_breakable(this);
00374   if (stmt) {
00375     fun->adjust_reloffset(out.size() + 3);
00376     stmt->gen(stmt_code, fun);  // Generate statement's code.
00377     fun->adjust_reloffset(-out.size() - 3);
00378   }
00379   int stmtlen = stmt_code.size();
00380           // Get distance back to top, including
00381           //   a CONVERSE & JMP back to top.
00382   long dist = stmtlen + 3 + 3;
00383   stmt_code.push_back((char) UC_JMP); // Generate JMP back to top.
00384   Write2(stmt_code, -dist);
00385   stmtlen = stmt_code.size(); // Get total length.
00386   fun->end_breakable(this, stmt_code);
00387   out.push_back((char) UC_CONVERSE);  // Put CONVERSE at top.
00388   Write2(out, stmtlen);   // Skip around body if no choices.
00389           // Write out body.
00390   out.insert(out.end(), stmt_code.begin(), stmt_code.end());
00391   out.push_back((char) UC_CONVERSELOC); // Past CONVERSE loop.
00392   }
00393 
00394 /*
00395  *  Generate a call to an intrinsic with 0 or 1 parameter.
00396  */
00397 static void Call_intrinsic
00398   (
00399   vector<char>& out,
00400   Uc_function *fun,   // Function we're in.
00401   Uc_intrinsic_symbol *intr,  // What to call.
00402   Uc_expression *parm0 = 0  // Parm, or null.
00403   )
00404   {
00405           // Create parms. list.
00406   Uc_array_expression *parms = new Uc_array_expression;
00407   if (parm0)
00408     parms->add(parm0);
00409   Uc_call_expression *fcall = new Uc_call_expression(intr, parms, fun);
00410   Uc_call_statement fstmt(fcall);
00411   fstmt.gen(out, fun);
00412   parms->clear();     // DON'T want to delete parm0.
00413   }
00414 
00415 /*
00416  *  Generate code.
00417  */
00418 
00419 void Uc_converse_case_statement::gen
00420   (
00421   vector<char>& out,    // Contains all CASE statements up to
00422           //   this point.
00423   Uc_function *fun
00424   )
00425   {
00426   out.push_back((char) UC_PUSHS); // Gen. string comparison.
00427   Write2(out, string_offset);
00428   out.push_back((char) UC_CMPS);  // Generate comparison.
00429   Write2(out, 1);     // # strings on stack.
00430   int to_top_index = out.size();  // Remember this spot to fill in.
00431   Write2(out, 0);     // Place holder.
00432   if (remove)     // Remove answer?
00433     {
00434     Uc_string_expression str(string_offset);
00435     Call_intrinsic(out, fun,
00436         Uc_function::get_remove_answer(), &str);
00437     }
00438   if (statements)     // Generate statement's code.
00439     statements->gen(out, fun);
00440           // Get distance back to top, including
00441           //   this JMP
00442           //   and the CONVERSE above 'out' code.
00443   long dist = out.size() + 3 + 3;
00444           // Generate JMP to start of conv.
00445   out.push_back((char) UC_JMP);
00446   Write2(out, -dist);
00447           // Fill in offset in CMPS.
00448   Write2(out, to_top_index, out.size() - (to_top_index + 2));
00449   }
00450 
00451 /*
00452  *  Delete.
00453  */
00454 
00455 Uc_converse2_statement::~Uc_converse2_statement
00456   (
00457   )
00458   {
00459   delete answers;
00460   delete cases;
00461   }
00462 
00463 /*
00464  *  Generate code.
00465  */
00466 
00467 void Uc_converse2_statement::gen
00468   (
00469   vector<char>& out,
00470   Uc_function *fun
00471   )
00472   {
00473   if (nest++ > 0)     // Not the outermost?
00474           // Generate a 'push_answers()'.
00475     Call_intrinsic(out, fun, Uc_function::get_push_answers());
00476   if (answers)      // Add desired answers.
00477     Call_intrinsic(out, fun, 
00478         Uc_function::get_add_answer(), answers);
00479   vector<char> stmt_code;
00480   fun->start_breakable(this);
00481   if (cases) 
00482     {
00483     fun->adjust_reloffset(out.size() + 3);
00484     cases->gen(stmt_code, fun); // Generate statement's code.
00485     fun->adjust_reloffset(-out.size() - 3);
00486     }
00487   int stmtlen = stmt_code.size();
00488           // Get distance back to top, including
00489           //   a CONVERSE & JMP back to top.
00490   long dist = stmtlen + 3 + 3;
00491   stmt_code.push_back((char) UC_JMP); // Generate JMP back to top.
00492   Write2(stmt_code, -dist);
00493   stmtlen = stmt_code.size(); // Get total length.
00494   fun->end_breakable(this, stmt_code);
00495   out.push_back((char) UC_CONVERSE);  // Put CONVERSE at top.
00496   Write2(out, stmtlen);   // Skip around body if no choices.
00497           // Write out body.
00498   out.insert(out.end(), stmt_code.begin(), stmt_code.end());
00499   out.push_back((char) UC_CONVERSELOC); // Past CONVERSE loop.
00500   if (--nest > 0)     // Not the outermost?
00501           // Generate a 'pop_answers()'.
00502     Call_intrinsic(out, fun, Uc_function::get_pop_answers());
00503   }
00504 
00505 /*
00506  *  Generate code.
00507  */
00508 
00509 void Uc_message_statement::gen
00510   (
00511   vector<char>& out,
00512   Uc_function *fun
00513   )
00514   {
00515   if (!msgs)
00516     return;
00517   const std::vector<Uc_expression*>& exprs = msgs->get_exprs();
00518   for (std::vector<Uc_expression*>::const_iterator it = exprs.begin();
00519           it != exprs.end(); ++it)
00520     {
00521     Uc_expression *msg = *it;
00522           // A known string?
00523     int offset = msg->get_string_offset();
00524     if (offset >= 0)
00525       {
00526       out.push_back((char) UC_ADDSI);
00527       Write2(out, offset);
00528       }
00529     else
00530       {
00531       Uc_var_symbol *var = msg->need_var(out, fun);
00532       if (var)  // Shouldn't fail.
00533         {
00534         out.push_back((char) UC_ADDSV);
00535         Write2(out, var->get_offset());
00536         }
00537       }
00538     }
00539   }
00540 
00541 /*
00542  *  Generate code.
00543  */
00544 
00545 void Uc_say_statement::gen
00546   (
00547   vector<char>& out,
00548   Uc_function *fun
00549   )
00550   {
00551           // Add the messages.
00552   Uc_message_statement::gen(out, fun);
00553   out.push_back((char) UC_SAY);   // Show on screen.
00554   }
00555 
00556 /*
00557  *  Create.
00558  */
00559 
00560 Uc_call_statement::Uc_call_statement
00561   (
00562   Uc_call_expression *f
00563   ) : function_call(f)
00564   {
00565   if (function_call)
00566     function_call->set_no_return();
00567   }
00568 
00569 /*
00570  *  Delete.
00571  */
00572 
00573 Uc_call_statement::~Uc_call_statement
00574   (
00575   )
00576   {
00577   delete function_call;
00578   }
00579 
00580 /*
00581  *  Generate code.
00582  */
00583 
00584 void Uc_call_statement::gen
00585   (
00586   vector<char>& out,
00587   Uc_function *fun
00588   )
00589   {
00590   function_call->gen_value(out);  // (We set 'no_return'.)
00591   }

Generated on Mon Jul 9 14:42:51 2007 for ExultEngine by  doxygen 1.5.1