ucfun.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 <cassert>
00031 #include "ucfun.h"
00032 #include "ucstmt.h"
00033 #include "utils.h"
00034 #include "opcodes.h"
00035 #include "ucexpr.h"     /* Needed only for Write2(). */
00036 
00037 using std::strlen;
00038 using std::memcpy;
00039 
00040 Uc_scope Uc_function::globals(0); // Stores intrinic symbols.
00041 vector<Uc_intrinsic_symbol *> Uc_function::intrinsics;
00042 int Uc_function::num_global_statics = 0;
00043 int Uc_function::add_answer = -1, Uc_function::remove_answer = -1,
00044   Uc_function::push_answers = -1, Uc_function::pop_answers = -1,
00045   Uc_function::show_face = -1, Uc_function::remove_face = -1;
00046 
00047 /*
00048  *  Create function, and add to global symbol table.
00049  */
00050 
00051 Uc_function::Uc_function
00052   (
00053   Uc_function_symbol *p
00054   ) : top(0), proto(p), cur_scope(&top), num_parms(0),
00055       num_locals(0), num_statics(0), text_data(0), text_data_size(0),
00056       statement(0), reloffset(0)
00057   {
00058   char *nm = (char *) proto->get_name();
00059   add_global_function_symbol(proto);// Add prototype to globals.
00060 #if 0
00061   if (!globals.search(nm))    
00062     globals.add(proto);
00063   else
00064     {
00065     char buf[100];
00066     sprintf(buf, "Name '%s' already defined", nm);
00067     Uc_location::yyerror(buf);
00068     }
00069 #endif
00070   const std::vector<char *>& parms = proto->get_parms();
00071   for (std::vector<char *>::const_iterator it = parms.begin();
00072         it != parms.end(); it++)
00073     add_symbol(*it);
00074   num_parms = num_locals;   // Set counts.
00075   num_locals = 0;
00076   }
00077 
00078 /*
00079  *  Delete.
00080  */
00081 
00082 Uc_function::~Uc_function
00083   (
00084   )
00085   {
00086   delete statement;
00087   delete proto;
00088 
00089   std::map<std::string, Uc_label*>::iterator iter;
00090   for (iter = labels.begin(); iter != labels.end(); ++iter)
00091     delete iter->second;
00092   }
00093 
00094 /*
00095  *  Check for a duplicate symbol and print an error.
00096  *
00097  *  Output: true if dup., with error printed.
00098  */
00099 
00100 bool Uc_function::is_dup
00101   (
00102   Uc_scope *scope,
00103   char *nm
00104   )
00105   {
00106   Uc_symbol *sym = scope->search(nm);
00107   if (sym)      // Already in scope?
00108     {
00109     char msg[180];
00110     sprintf(msg, "Symbol '%s' already declared", nm);
00111     Uc_location::yyerror(msg);
00112     return true;
00113     }
00114   return false;
00115   }
00116 
00117 /*
00118  *  Find a label in this function
00119  *
00120  *  Output: label, or 0 if not found
00121  */
00122 
00123 Uc_label *Uc_function::search_label(char *nm)
00124 {
00125   std::map<std::string,Uc_label*>::iterator iter;
00126   iter = labels.find(nm);
00127   if (iter != labels.end())
00128     return iter->second;
00129   return 0;
00130 }
00131 
00132 /*
00133  *  Add a new variable to the current scope.
00134  *
00135  *  Output: New sym, or 0 if already declared.
00136  */
00137 
00138 Uc_var_symbol *Uc_function::add_symbol
00139   (
00140   char *nm
00141   )
00142   {
00143   if (is_dup(cur_scope, nm))
00144     return 0;
00145           // Create & assign slot.
00146   Uc_var_symbol *var = new Uc_var_symbol(nm, num_parms + num_locals++);
00147   cur_scope->add(var);
00148   return var;
00149   }
00150 
00151 /*
00152  *  Add a new static variable to the current scope.
00153  */
00154 
00155 void Uc_function::add_static
00156   (
00157   char *nm
00158   )
00159   {
00160   if (is_dup(cur_scope, nm))
00161     return;
00162           // Create & assign slot.
00163   Uc_var_symbol *var = new Uc_static_var_symbol(nm, num_statics++);
00164   cur_scope->add(var);
00165   }
00166 
00167 /*
00168  *  Add a new string constant to the current scope.
00169  */
00170 
00171 Uc_symbol *Uc_function::add_string_symbol
00172   (
00173   char *nm,
00174   char *text
00175   )
00176   {
00177   if (is_dup(cur_scope, nm))
00178     return 0;
00179           // Create & assign slot.
00180   Uc_symbol *sym = new Uc_string_symbol(nm, add_string(text));
00181   cur_scope->add(sym);
00182   return sym;
00183   }
00184 
00185 /*
00186  *  Add a new integer constant variable to the current scope.
00187  *
00188  *  Output: New sym, or 0 if already declared.
00189  */
00190 
00191 Uc_symbol *Uc_function::add_int_const_symbol
00192   (
00193   char *nm,
00194   int value
00195   )
00196   {
00197   if (is_dup(cur_scope, nm))
00198     return 0;
00199           // Create & assign slot.
00200   Uc_const_int_symbol *var = new Uc_const_int_symbol(nm, value);
00201   cur_scope->add(var);
00202   return var;
00203   }
00204 
00205 /*
00206  *  Add a new integer constant variable to the global scope.
00207  *
00208  *  Output: New sym, or 0 if already declared.
00209  */
00210 
00211 Uc_symbol *Uc_function::add_global_int_const_symbol
00212   (
00213   char *nm,
00214   int value
00215   )
00216   {
00217   if (is_dup(&globals, nm))
00218     return 0;
00219           // Create & assign slot.
00220   Uc_const_int_symbol *var = new Uc_const_int_symbol(nm, value);
00221   globals.add(var);
00222   return var;
00223   }
00224 
00225 /*
00226  *  Add a global static.
00227  */
00228 
00229 void Uc_function::add_global_static
00230   (
00231   char *nm
00232   )
00233   {
00234   if (is_dup(&globals, nm))
00235     return;
00236   num_global_statics++;   // These start with 1.
00237           // Create & assign slot.
00238   Uc_var_symbol *var = new Uc_static_var_symbol(nm, 
00239               -num_global_statics);
00240   globals.add(var);
00241   }
00242 
00243 /*
00244  *  Add a string to the data area.
00245  *
00246  *  Output: offset of string.
00247  */
00248 
00249 int Uc_function::add_string
00250   (
00251   char *text
00252   )
00253   {
00254           // Search for an existing string.
00255   std::map<std::string, int>::const_iterator exist = text_map.find(text);
00256   if (exist != text_map.end())
00257     return (*exist).second;
00258   int offset = text_data_size;  // This is where it will go.
00259   int textlen = strlen(text) + 1; // Got to include ending null.
00260   char *new_text_data = new char[text_data_size + textlen];
00261   if (text_data_size)   // Copy over old.
00262     memcpy(new_text_data, text_data, text_data_size);
00263           // Append new.
00264   memcpy(new_text_data + text_data_size, text, textlen);
00265   delete text_data;
00266   text_data = new_text_data;
00267   text_data_size += textlen;
00268   text_map[text] = offset;  // Store map entry.
00269   return offset;
00270   }
00271 
00272 /*
00273  *  Find the (unique) string for a given prefix.
00274  *
00275  *  Output: Offset of string.  Error printed if more than one.
00276  *    0 if not found, with error printed.
00277  */
00278 
00279 int Uc_function::find_string_prefix
00280   (
00281   Uc_location& loc,   // For printing errors.
00282   const char *text
00283   )
00284   {
00285   int len = strlen(text);
00286           // Find 1st entry >= text.
00287   std::map<std::string, int>::const_iterator exist = 
00288           text_map.lower_bound(text);
00289   if (exist == text_map.end() ||
00290       strncmp(text, (*exist).first.c_str(), len) != 0)
00291     {
00292     char *buf = new char[len + 100];
00293     sprintf(buf, "Prefix '%s' matches no string in this function",
00294                   text);
00295     loc.error(buf);
00296     delete buf;
00297     return 0;
00298     }
00299   std::map<std::string, int>::const_iterator next = exist;
00300   ++next;
00301   if (next != text_map.end() &&
00302       strncmp(text, (*next).first.c_str(), len) == 0)
00303     {
00304     char *buf = new char[len + 100];
00305     sprintf(buf, "Prefix '%s' matches more than one string", text);
00306     loc.error(buf);
00307     delete buf;
00308     }
00309   return (*exist).second;   // Return offset.
00310   }
00311 
00312 /*
00313  *  Start a loop.
00314  */
00315 
00316 void Uc_function::start_breakable
00317   (
00318   Uc_statement *s     // Loop.
00319   )
00320   {
00321   breakables.push_back(s);
00322   breaks.push_back(-1);   // Set marker in 'break' list.
00323   }
00324 
00325 /*
00326  *  Fix up stuff when a loop's body has been generated.
00327  */
00328 
00329 void Uc_function::end_breakable
00330   (
00331   Uc_statement *s,    // Loop.  For verification.
00332   vector<char>& stmt_code
00333   )
00334   {
00335           // Just make sure things are right.
00336   assert(!breakables.empty() && s == breakables.back());
00337   breakables.pop_back();
00338   int stmtlen = stmt_code.size();
00339           // Fix all the 'break' statements,
00340           //   going backwards.
00341   while (!breaks.empty() && breaks.back() >= 0)
00342     {     // Get offset within loop.
00343     int break_offset = breaks.back();
00344     breaks.pop_back();  // Remove from end of list.
00345     assert(break_offset < stmtlen - 2);
00346           // Store offset.
00347     Write2(stmt_code, break_offset + 1, 
00348             stmtlen - (break_offset + 3));
00349     }
00350   assert(!breaks.empty() && breaks.back() == -1);
00351   breaks.pop_back();    // Remove marker (-1).
00352   }
00353 
00354 /*
00355  *  Store a 'break' statement's offset so it can be filled in at the end
00356  *  of the current loop.
00357  */
00358 
00359 void Uc_function::add_break
00360   (
00361   int op_offset     // Offset in loop's code of JMP.
00362   )
00363   {
00364   assert(op_offset >= 0);
00365   if (breakables.empty())   // Not in a loop?
00366     Uc_location::yyerror("'break' is not valid here");
00367   else
00368     breaks.push_back(op_offset);
00369   }
00370 
00371 /*
00372  *  Lookup/add a link to an external function.
00373  *
00374  *  Output: Link offset.
00375  */
00376 
00377 int Uc_function::link
00378   (
00379   Uc_function_symbol *fun
00380   )
00381   {
00382   for (std::vector<Uc_function_symbol *>::const_iterator it = links.begin();
00383             it != links.end(); it++)
00384     if (*it == fun)   // Found it?  Return offset.
00385       return (it - links.begin());
00386   int offset = links.size();  // Going to add it.
00387   links.push_back(fun);
00388   return offset;
00389   }
00390 
00391 
00392 void Uc_function::link_labels(vector<char>& code)
00393 {
00394   std::map<std::string, Uc_label*>::iterator iter;
00395   for (iter = labels.begin(); iter != labels.end(); ++iter) {
00396     Uc_label *label = iter->second;
00397     if (label->is_valid()) {
00398       int target = label->get_offset(); 
00399       std::vector<int>& references = label->get_references();
00400       std::vector<int>::iterator i;
00401       for (i = references.begin(); i != references.end(); ++i) {
00402         int offset = (*i) + 1;
00403         Write2(code, offset, target - (offset + 2));
00404       }
00405     }
00406   }
00407 }
00408 
00409 /*
00410  *  Generate Usecode.
00411  */
00412 
00413 void Uc_function::gen
00414   (
00415   std::ostream& out
00416   )
00417   {
00418           // Start with function #.
00419   Write2(out, proto->get_usecode_num());
00420   vector<char> code;    // Generate code here first.
00421   code.reserve(30000);
00422   if (statement)
00423     statement->gen(code, this);
00424   code.push_back((char) UC_RET);  // Always end with a RET.
00425   link_labels(code);
00426   int codelen = code.size();  // Get its length.
00427   int num_links = links.size();
00428           // Total: text_data_size + data + 
00429           //   #args + #locals + #links + links +
00430           //   codelen.
00431   int totallen =  2 + text_data_size + 2 + 2 + 2 + 2*num_links + codelen;
00432   Write2(out, totallen);
00433   Write2(out, text_data_size);    // Now data.
00434   out.write(text_data, text_data_size);
00435   Write2(out, num_parms);   // Counts.
00436   Write2(out, num_locals);
00437   Write2(out, num_links);
00438           // Write external links.
00439   for (std::vector<Uc_function_symbol *>::const_iterator it = 
00440         links.begin(); it != links.end(); it++)
00441     Write2(out, (*it)->get_usecode_num());
00442   char *ucstr = &code[0];   // Finally, the code itself.
00443   out.write(ucstr, codelen);
00444   out.flush();
00445   }
00446 
00447 #ifndef __STRING
00448 #if defined __STDC__ && __STDC__
00449 #define __STRING(x) #x
00450 #else
00451 #define __STRING(x) "x"
00452 #endif
00453 #endif
00454 
00455 /*
00456  *  Tables of usecode intrinsics:
00457  */
00458 #define USECODE_INTRINSIC_PTR(NAME) __STRING(UI_##NAME)
00459 
00460 const char *bg_intrinsic_table[] =
00461   {
00462 #include "../bgintrinsics.h"
00463   };
00464 
00465 const char *si_intrinsic_table[] = 
00466   {
00467 #include "../siintrinsics.h"
00468   };
00469 
00470 /*
00471  *  Add one of the intrinsic tables to the 'intrinsics' scope.
00472  */
00473 
00474 void Uc_function::set_intrinsics
00475   (
00476   Intrinsic_type ty
00477   )
00478   {
00479   int cnt;
00480   const char **table;
00481   if (ty == bg)
00482     {
00483     table = bg_intrinsic_table;
00484     cnt = sizeof(bg_intrinsic_table)/sizeof(bg_intrinsic_table[0]);
00485     add_answer = 5;
00486     remove_answer = 6;
00487     push_answers = 7;
00488     pop_answers = 8;
00489     }
00490   else
00491     {
00492     table = si_intrinsic_table;
00493     cnt = sizeof(si_intrinsic_table)/sizeof(si_intrinsic_table[0]);
00494     add_answer = 0xc;
00495     remove_answer = 0xd;
00496     push_answers = 0xe;
00497     pop_answers = 0xf;
00498     }
00499   show_face = 3;
00500   remove_face = 4;
00501   intrinsics.resize(cnt);
00502   for (int i = 0; i < cnt; i++)
00503     {
00504     char *nm = (char *)table[i];
00505     Uc_intrinsic_symbol *sym = new Uc_intrinsic_symbol(nm, i);
00506     intrinsics[i] = sym;  // Store in indexed list.
00507     if (!globals.search(nm))
00508           // ++++Later, get num parms.
00509       globals.add(sym);
00510     }
00511   }
00512 

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