Selaa lähdekoodia

add 1.1 elements: #for, #while, #mkdir

David Rose 23 vuotta sitten
vanhempi
sitoutus
b7155fcde1
5 muutettua tiedostoa jossa 250 lisäystä ja 9 poistoa
  1. 1 1
      ppremake/config_msvc.h
  2. 1 1
      ppremake/configure.in
  3. 237 5
      ppremake/ppCommandFile.cxx
  4. 10 1
      ppremake/ppCommandFile.h
  5. 1 1
      ppremake/ppScope.cxx

+ 1 - 1
ppremake/config_msvc.h

@@ -80,5 +80,5 @@
  **         Also be sure to change the version number        **
  **             at the beginning of configure.in.            **
  ****************                              ****************/
-#define VERSION "1.05"
+#define VERSION "1.1"
 /****************  UPDATE VERSION NUMBER HERE  ****************/

+ 1 - 1
ppremake/configure.in

@@ -5,7 +5,7 @@ dnl ****************  UPDATE VERSION NUMBER HERE  ****************
 dnl **         Also be sure to change the version number        **
 dnl **                at the end of config_msvc.h.              **
 dnl ****************                              ****************
-AM_INIT_AUTOMAKE(ppremake, 1.05)
+AM_INIT_AUTOMAKE(ppremake, 1.1)
 dnl ****************  UPDATE VERSION NUMBER HERE  ****************
 
 AM_CONFIG_HEADER(config.h)

+ 237 - 5
ppremake/ppCommandFile.cxx

@@ -491,6 +491,11 @@ end_read() {
       cerr << "Unclosed begin " << _block_nesting->_name << "\n";
       break;
 
+    case BS_while:
+    case BS_nested_while:
+      cerr << "Unclosed while " << _block_nesting->_name << "\n";
+      break;
+
     case BS_forscopes:
     case BS_nested_forscopes:
       cerr << "Unclosed forscopes " << _block_nesting->_name << "\n";
@@ -597,6 +602,12 @@ handle_command(const string &line) {
   } else if (_command == "begin") {
     return handle_begin_command();
 
+  } else if (_command == "while") {
+    return handle_while_command();
+
+  } else if (_command == "for") {
+    return handle_for_command();
+
   } else if (_command == "forscopes") {
     return handle_forscopes_command();
 
@@ -645,6 +656,9 @@ handle_command(const string &line) {
   } else if (_command == "error") {
     return handle_error_command();
 
+  } else if (_command == "mkdir") {
+    return handle_mkdir_command();
+
   } else if (_command == "defer") {
     return handle_defer_command();
 
@@ -831,6 +845,70 @@ handle_begin_command() {
   return true;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: PPCommandFile::handle_while_command
+//       Access: Protected
+//  Description: Handles the #while command: repeat a block of
+//               commands while a condition is true (nonempty).
+//               Unlike many of the other block commands, this does
+//               not begin a new scope.
+////////////////////////////////////////////////////////////////////
+bool PPCommandFile::
+handle_while_command() {
+  BlockState state = _in_for ? BS_nested_while : BS_while;
+  string name = trim_blanks(_params);
+  BlockNesting *nest = new BlockNesting(state, name);
+  nest->push(this);
+
+  if (!_in_for) {
+    _in_for = true;
+    _saved_lines.clear();
+  }
+
+  return true;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PPCommandFile::handle_for_command
+//       Access: Protected
+//  Description: Handles the #for command: repeat a block of
+//               commands with a loop variable iterating over a range
+//               of numeric values.
+////////////////////////////////////////////////////////////////////
+bool PPCommandFile::
+handle_for_command() {
+  // We get the name of the variable out first.
+  size_t p = _scope->scan_to_whitespace(_params);
+  string name = _params.substr(0, p);
+
+  if (name.empty()) {
+    cerr << "#for without varname\n";
+    return false;
+  }
+
+  // The rest is the comma-delimited range of values.
+  vector<string> words;
+  _scope->tokenize_params(_params.substr(p), words, true);
+  if (words.size() != 2 && words.size() != 3) {
+    cerr << "Invalid numeric range: '" << _params.substr(p) 
+         << "' for #for " << name << "\n";
+    return false;
+  }
+
+  BlockState state = _in_for ? BS_nested_for : BS_for;
+  BlockNesting *nest = new BlockNesting(state, name);
+  nest->push(this);
+
+  if (!_in_for) {
+    _in_for = true;
+    _saved_lines.clear();
+
+    nest->_words.swap(words);
+  }
+
+  return true;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: PPCommandFile::handle_forscopes_command
 //       Access: Protected
@@ -1034,12 +1112,12 @@ handle_output_command() {
       return false;
     }
     
-    string prefix = _scope->expand_variable("DIRPREFIX");
     if (filename[0] != '/') {
+      string prefix = _scope->expand_variable("DIRPREFIX");
       filename = prefix + filename;
     }
 
-    nest->_filename = filename;
+    nest->_params = filename;
 
     // Generate an in-memory copy of the file first.
     _write_state = new WriteState(*_write_state);
@@ -1083,7 +1161,21 @@ handle_end_command() {
     return false;
   }
 
-  if (nest->_state == BS_forscopes) {
+  if (nest->_state == BS_while) {
+    // Now replay all of the saved lines.
+    _in_for = false;
+    if (!replay_while(nest->_name)) {
+      return false;
+    }
+
+  } else if (nest->_state == BS_for) {
+    // Now replay all of the saved lines.
+    _in_for = false;
+    if (!replay_for(nest->_name, nest->_words)) {
+      return false;
+    }
+
+  } else if (nest->_state == BS_forscopes) {
     // Now replay all of the saved lines.
     _in_for = false;
     if (!replay_forscopes(nest->_name)) {
@@ -1126,7 +1218,7 @@ handle_end_command() {
   } else if (nest->_state == BS_output) {
     if (!_in_for) {
       if (!nest->_output) {
-        cerr << "Error while writing " << nest->_filename << "\n";
+        cerr << "Error while writing " << nest->_params << "\n";
         return false;
       }
 
@@ -1135,7 +1227,7 @@ handle_end_command() {
 
       nest->_output << ends;
       const char *generated_file = nest->_output.str();
-      if (!compare_output(generated_file, nest->_filename,
+      if (!compare_output(generated_file, nest->_params,
                           (nest->_flags & OF_notouch) != 0)) {
         return false;
       }
@@ -1327,6 +1419,34 @@ handle_error_command() {
   return false;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: PPCommandFile::handle_mkdir_command
+//       Access: Protected
+//  Description: Handles the #mkdir command: create a directory or
+//               directories.
+////////////////////////////////////////////////////////////////////
+bool PPCommandFile::
+handle_mkdir_command() {
+  vector<string> words;
+  tokenize_whitespace(_scope->expand_string(_params), words);
+
+  if (words.empty()) {
+    cerr << "No directory name specifed to #mkdir.\n";
+  } else {
+    vector<string>::const_iterator wi;
+    for (wi = words.begin(); wi != words.end(); ++wi) {
+      Filename dirname(*wi, ".");
+      if (!dirname.make_dir()) {
+        if (!dirname.is_directory()) {
+          cerr << "Unable to create directory " << *wi << "\n";
+        }
+      }
+    }
+  }
+
+  return true;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: PPCommandFile::handle_defer_command
 //       Access: Protected
@@ -1572,6 +1692,118 @@ include_file(Filename filename) {
   return true;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: PPCommandFile::replay_while
+//       Access: Protected
+//  Description: Replays all the lines that were saved during a
+//               previous #while..#end block.
+////////////////////////////////////////////////////////////////////
+bool PPCommandFile::
+replay_while(const string &name) {
+  assert(!_in_for);
+
+  bool okflag = true;
+
+  vector<string> lines;
+  lines.swap(_saved_lines);
+
+  // Remove the #end command.  This will fail if someone makes an #end
+  // command that spans multiple lines.  Don't do that.
+  assert(!lines.empty());
+  lines.pop_back();
+
+  // Now replay all of the saved lines.
+  BlockNesting *saved_block = _block_nesting;
+  IfNesting *saved_if = _if_nesting;
+
+  while (!_scope->expand_string(name).empty()) {
+    vector<string>::const_iterator li;
+    for (li = lines.begin(); li != lines.end() && okflag; ++li) {
+      okflag = read_line(*li);
+    }
+  }
+
+  if (saved_block != _block_nesting || saved_if != _if_nesting) {
+    cerr << "Misplaced #end or #endif.\n";
+    okflag = false;
+  }
+
+  return okflag;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PPCommandFile::replay_for
+//       Access: Protected
+//  Description: Replays all the lines that were saved during a
+//               previous #for..#end block.
+////////////////////////////////////////////////////////////////////
+bool PPCommandFile::
+replay_for(const string &name, const vector<string> &words) {
+  assert(!_in_for);
+
+  bool okflag = true;
+
+  vector<string> lines;
+  lines.swap(_saved_lines);
+
+  // Remove the #end command.  This will fail if someone makes an #end
+  // command that spans multiple lines.  Don't do that.
+  assert(!lines.empty());
+  lines.pop_back();
+
+  // Expand the variable name.
+  string varname = _scope->expand_string(name);
+
+  // Get out the numeric range.
+  int range[3] = {0, 0, 1};
+  assert(words.size() <= 3);
+  for (int i = 0; i < (int)words.size(); i++) {
+    const char *param = words[i].c_str();
+    char *n;
+    range[i] = strtol(param, &n, 10);
+    if (n == param) {
+      cerr << "Invalid integer in #for: " << param << "\n";
+      return false;
+    }
+  }
+
+  if (range[2] == 0) {
+    cerr << "Step by zero in #for " << name << "\n";
+    return false;
+  }
+
+  // Now replay all of the saved lines.
+  BlockNesting *saved_block = _block_nesting;
+  IfNesting *saved_if = _if_nesting;
+  int index_var;
+
+  if (range[2] > 0) {
+    for (index_var = range[0]; index_var <= range[1]; index_var += range[2]) {
+      _scope->define_variable(varname, _scope->format_int(index_var));
+      vector<string>::const_iterator li;
+      for (li = lines.begin(); li != lines.end() && okflag; ++li) {
+        okflag = read_line(*li);
+      }
+    }
+  } else {
+    for (index_var = range[0]; index_var >= range[1]; index_var += range[2]) {
+      _scope->define_variable(varname, _scope->format_int(index_var));
+      vector<string>::const_iterator li;
+      for (li = lines.begin(); li != lines.end() && okflag; ++li) {
+        okflag = read_line(*li);
+      }
+    }
+  }
+  _scope->define_variable(varname, _scope->format_int(index_var));
+
+  if (saved_block != _block_nesting || saved_if != _if_nesting) {
+    cerr << "Misplaced #end or #endif.\n";
+    okflag = false;
+  }
+
+  return okflag;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: PPCommandFile::replay_forscopes
 //       Access: Protected

+ 10 - 1
ppremake/ppCommandFile.h

@@ -45,6 +45,8 @@ protected:
   bool handle_endif_command();
 
   bool handle_begin_command();
+  bool handle_while_command();
+  bool handle_for_command();
   bool handle_forscopes_command();
   bool handle_foreach_command();
   bool handle_formap_command();
@@ -59,6 +61,7 @@ protected:
   bool handle_sinclude_command();
   bool handle_call_command();
   bool handle_error_command();
+  bool handle_mkdir_command();
 
   bool handle_defer_command();
   bool handle_define_command();
@@ -68,6 +71,8 @@ protected:
   bool handle_push_command();
 
   bool include_file(Filename filename);
+  bool replay_while(const string &name);
+  bool replay_for(const string &name, const vector<string> &words);
   bool replay_forscopes(const string &name);
   bool replay_foreach(const string &varname, const vector<string> &words);
   bool replay_formap(const string &varname, const string &mapvar);
@@ -111,6 +116,10 @@ private:
 
   enum BlockState {
     BS_begin,
+    BS_while,
+    BS_nested_while,
+    BS_for,
+    BS_nested_for,
     BS_forscopes,
     BS_nested_forscopes,
     BS_foreach,
@@ -157,7 +166,7 @@ private:
     IfNesting *_if;
     WriteState *_write_state;
     PPScope *_scope;
-    string _filename;
+    string _params;
     ostrstream _output;
     vector<string> _words;
     int _flags;

+ 1 - 1
ppremake/ppScope.cxx

@@ -2601,7 +2601,7 @@ expand_minus(const string &params) {
   int num_words = words.size();
 
   if (num_words == 1) {
-    // Simular unary minus by setting the first operand to 0.
+    // Simulate unary minus by setting the first operand to 0.
     results[0] = 0.0;
     
   } else if (num_words != 2) {