Browse Source

*** empty log message ***

David Rose 25 years ago
parent
commit
b376e16a00
4 changed files with 292 additions and 194 deletions
  1. 1 1
      ppremake/configure.in
  2. 274 188
      ppremake/ppCommandFile.cxx
  3. 16 5
      ppremake/ppCommandFile.h
  4. 1 0
      ppremake/ppScope.cxx

+ 1 - 1
ppremake/configure.in

@@ -1,6 +1,6 @@
 dnl Process this file with autoconf to produce a configure script.
 dnl Process this file with autoconf to produce a configure script.
 AC_INIT(ppremake.cxx)
 AC_INIT(ppremake.cxx)
-AM_INIT_AUTOMAKE(ppremake, 0.51)
+AM_INIT_AUTOMAKE(ppremake, 0.52)
 AM_CONFIG_HEADER(config.h)
 AM_CONFIG_HEADER(config.h)
 
 
 AC_PREFIX_DEFAULT(/usr/local/panda)
 AC_PREFIX_DEFAULT(/usr/local/panda)

+ 274 - 188
ppremake/ppCommandFile.cxx

@@ -14,9 +14,49 @@
 #include <unistd.h>
 #include <unistd.h>
 #include <sys/types.h>
 #include <sys/types.h>
 #include <utime.h>
 #include <utime.h>
+#include <assert.h>
 
 
 static const string begin_comment(BEGIN_COMMENT);
 static const string begin_comment(BEGIN_COMMENT);
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: PPCommandFile::IfNesting::Constructor
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+PPCommandFile::IfNesting::
+IfNesting(IfState state) :
+  _state(state)
+{
+  _block = (PPCommandFile::BlockNesting *)NULL;
+  _next = (PPCommandFile::IfNesting *)NULL;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PPCommandFile::IfNesting::push
+//       Access: Public
+//  Description: Adds this IfNesting object to the top of the
+//               nesting stack.
+////////////////////////////////////////////////////////////////////
+void PPCommandFile::IfNesting::
+push(PPCommandFile *file) {
+  _block = file->_block_nesting;
+  _next = file->_if_nesting;
+  file->_if_nesting = this;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PPCommandFile::IfNesting::pop
+//       Access: Public
+//  Description: Removes this IfNesting object from the top of the
+//               nesting stack, and restores the command file's
+//               nesting state.
+////////////////////////////////////////////////////////////////////
+void PPCommandFile::IfNesting::
+pop(PPCommandFile *file) {
+  assert(file->_if_nesting == this);
+  file->_if_nesting = _next;
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: PPCommandFile::WriteState::Constructor
 //     Function: PPCommandFile::WriteState::Constructor
 //       Access: Public
 //       Access: Public
@@ -128,6 +168,58 @@ write_makefile_line(const string &line) {
   return true;
   return true;
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: PPCommandFile::BlockNesting::Constructor
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+PPCommandFile::BlockNesting::
+BlockNesting(BlockState state, const string &name) :
+  _state(state),
+  _name(name)
+{
+  _if = (PPCommandFile::IfNesting *)NULL;
+  _write_state = (PPCommandFile::WriteState *)NULL;
+  _scope = (PPScope *)NULL;
+  _tempnam = (char *)NULL;
+  _flags = 0;
+  _next = (PPCommandFile::BlockNesting *)NULL;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PPCommandFile::BlockNesting::push
+//       Access: Public
+//  Description: Adds this BlockNesting object to the top of the
+//               nesting stack.
+////////////////////////////////////////////////////////////////////
+void PPCommandFile::BlockNesting::
+push(PPCommandFile *file) {
+  _if = file->_if_nesting;
+  _write_state = file->_write_state;
+  _scope = file->_scope;
+  _next = file->_block_nesting;
+  file->_block_nesting = this;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PPCommandFile::BlockNesting::pop
+//       Access: Public
+//  Description: Removes this BlockNesting object from the top of the
+//               nesting stack, and restores the command file's
+//               nesting state.
+////////////////////////////////////////////////////////////////////
+void PPCommandFile::BlockNesting::
+pop(PPCommandFile *file) {
+  assert(file->_block_nesting == this);
+
+  if (file->_write_state != _write_state) {
+    delete file->_write_state;
+    file->_write_state = _write_state;
+  }
+  file->_scope = _scope;
+  file->_block_nesting = _next;
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: PPCommandFile::Constructor
 //     Function: PPCommandFile::Constructor
 //       Access: Public
 //       Access: Public
@@ -424,7 +516,7 @@ handle_command(const string &line) {
     _params = line.substr(p);
     _params = line.substr(p);
   }
   }
 
 
-  if (_params[_params.length() - 1] == '\\') {
+  if (!_params.empty() && _params[_params.length() - 1] == '\\') {
     // If the line ends with a backslash, there's more to come before
     // If the line ends with a backslash, there's more to come before
     // we can process the command.
     // we can process the command.
     _got_command = true;
     _got_command = true;
@@ -470,29 +562,30 @@ handle_command(const string &line) {
   } else if (_command == "formap") {
   } else if (_command == "formap") {
     return handle_formap_command();
     return handle_formap_command();
 
 
-  } else if (_command == "format") {
-    return handle_format_command();
-
-  } else if (_command == "output") {
-    return handle_output_command();
-
-  } else if (_command == "print") {
-    return handle_print_command();
-
   } else if (_command == "defsub") {
   } else if (_command == "defsub") {
     return handle_defsub_command(true);
     return handle_defsub_command(true);
 
 
   } else if (_command == "defun") {
   } else if (_command == "defun") {
     return handle_defsub_command(false);
     return handle_defsub_command(false);
 
 
+  } else if (_command == "output") {
+    return handle_output_command();
+
   } else if (_command == "end") {
   } else if (_command == "end") {
     return handle_end_command();
     return handle_end_command();
 
 
   } else if (_in_for) {
   } else if (_in_for) {
-    // If we're saving up #forscopes commands, we ignore any following
-    // commands for now.
+    // If we're currently saving up lines within a block sequence, we
+    // ignore all commands except for the block-related commands,
+    // above.
     return true;
     return true;
 
 
+  } else if (_command == "format") {
+    return handle_format_command();
+
+  } else if (_command == "print") {
+    return handle_print_command();
+
   } else if (_command == "include") {
   } else if (_command == "include") {
     return handle_include_command();
     return handle_include_command();
 
 
@@ -537,10 +630,8 @@ handle_if_command() {
     // If we're *already* inside a failed if, we don't have to
     // If we're *already* inside a failed if, we don't have to
     // evaluate this one, but we do need to record the nesting level.
     // evaluate this one, but we do need to record the nesting level.
 
 
-    IfNesting *nest = new IfNesting;
-    nest->_state = IS_done;
-    nest->_next = _if_nesting;
-    _if_nesting = nest;
+    IfNesting *nest = new IfNesting(IS_done);
+    nest->push(this);
 
 
   } else {
   } else {
 
 
@@ -548,20 +639,19 @@ handle_if_command() {
     // Otherwise the case is true.  However, if we're currently
     // Otherwise the case is true.  However, if we're currently
     // scanning #forscopes or something, we don't evaluate this at
     // scanning #forscopes or something, we don't evaluate this at
     // all, because it doesn't matter.
     // all, because it doesn't matter.
+
+    bool is_empty = true;
     if (!_in_for) {
     if (!_in_for) {
       _params = _scope->expand_string(_params);
       _params = _scope->expand_string(_params);
+      string::const_iterator si;
+      for (si = _params.begin(); si != _params.end() && is_empty; ++si) {
+	is_empty = isspace(*si);
+      }
     }
     }
     
     
-    bool is_empty = true;
-    string::const_iterator si;
-    for (si = _params.begin(); si != _params.end() && is_empty; ++si) {
-      is_empty = isspace(*si);
-    }
-    
-    IfNesting *nest = new IfNesting;
-    nest->_state = is_empty ? IS_off : IS_on;
-    nest->_next = _if_nesting;
-    _if_nesting = nest;
+    IfState state = is_empty ? IS_off : IS_on;
+    IfNesting *nest = new IfNesting(state);
+    nest->push(this);
   }
   }
 
 
   return true;
   return true;
@@ -591,14 +681,13 @@ handle_elif_command() {
 
 
   // If the parameter string evaluates to empty, the case is false.
   // If the parameter string evaluates to empty, the case is false.
   // Otherwise the case is true.
   // Otherwise the case is true.
+  bool is_empty = true;
   if (!_in_for) {
   if (!_in_for) {
     _params = _scope->expand_string(_params);
     _params = _scope->expand_string(_params);
-  }
-
-  bool is_empty = true;
-  string::const_iterator si;
-  for (si = _params.begin(); si != _params.end() && is_empty; ++si) {
-    is_empty = isspace(*si);
+    string::const_iterator si;
+    for (si = _params.begin(); si != _params.end() && is_empty; ++si) {
+      is_empty = isspace(*si);
+    }
   }
   }
 
 
   _if_nesting->_state = is_empty ? IS_off : IS_on;
   _if_nesting->_state = is_empty ? IS_off : IS_on;
@@ -645,7 +734,13 @@ handle_endif_command() {
   }
   }
 
 
   IfNesting *nest = _if_nesting;
   IfNesting *nest = _if_nesting;
-  _if_nesting = _if_nesting->_next;
+  nest->pop(this);
+
+  if (nest->_block != _block_nesting) {
+    cerr << "If block not closed within scoping block.\n";
+    return false;
+  }
+
   delete nest;
   delete nest;
 
 
   return true;
   return true;
@@ -661,39 +756,27 @@ handle_endif_command() {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 bool PPCommandFile::
 bool PPCommandFile::
 handle_begin_command() {
 handle_begin_command() {
-  BlockNesting *nest = new BlockNesting;
-  nest->_state = BS_begin;
-  nest->_name = trim_blanks(_scope->expand_string(_params));
-  nest->_write_state = _write_state;
-  nest->_scope = _scope;
-  nest->_next = _block_nesting;
-
-  if (contains_whitespace(nest->_name)) {
-    cerr << "Attempt to define scope named \"" << nest->_name 
+  string name = trim_blanks(_scope->expand_string(_params));
+  BlockNesting *nest = new BlockNesting(BS_begin, name);
+
+  if (contains_whitespace(name)) {
+    cerr << "Attempt to define scope named \"" << name 
 	 << "\".\nScope names may not contain whitespace.\n";
 	 << "\".\nScope names may not contain whitespace.\n";
     return false;
     return false;
   }
   }
 
 
-  if (nest->_name.find(SCOPE_DIRNAME_SEPARATOR) != string::npos) {
-    cerr << "Attempt to define scope named \"" << nest->_name 
+  if (name.find(SCOPE_DIRNAME_SEPARATOR) != string::npos) {
+    cerr << "Attempt to define scope named \"" << name 
 	 << "\".\nScope names may not contain the '"
 	 << "\".\nScope names may not contain the '"
 	 << SCOPE_DIRNAME_SEPARATOR << "' character.\n";
 	 << SCOPE_DIRNAME_SEPARATOR << "' character.\n";
     return false;
     return false;
   }
   }
 
 
-  _block_nesting = nest;
+  nest->push(this);
 
 
-  if (nest->_name == "global") {
-    // There's a special case for the named scope "global": this
-    // refers to the global scope, allowing us to define macros
-    // etc. that all scopes can see.
-    _scope = PPScope::get_bottom_scope();
-
-  } else {
-    PPScope *named_scope = _scope->get_named_scopes()->make_scope(nest->_name);
-    named_scope->set_parent(_scope);
-    _scope = named_scope;
-  }
+  PPScope *named_scope = _scope->get_named_scopes()->make_scope(name);
+  named_scope->set_parent(_scope);
+  _scope = named_scope;
 
 
   return true;
   return true;
 }
 }
@@ -708,14 +791,10 @@ handle_begin_command() {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 bool PPCommandFile::
 bool PPCommandFile::
 handle_forscopes_command() {
 handle_forscopes_command() {
-  BlockNesting *nest = new BlockNesting;
-  nest->_state = _in_for ? BS_nested_forscopes : BS_forscopes;
-  nest->_name = trim_blanks(_scope->expand_string(_params));
-  nest->_write_state = _write_state;
-  nest->_scope = _scope;
-  nest->_next = _block_nesting;
-
-  _block_nesting = nest;
+  BlockState state = _in_for ? BS_nested_forscopes : BS_forscopes;
+  string name = trim_blanks(_scope->expand_string(_params));
+  BlockNesting *nest = new BlockNesting(state, name);
+  nest->push(this);
 
 
   if (!_in_for) {
   if (!_in_for) {
     _in_for = true;
     _in_for = true;
@@ -748,18 +827,13 @@ handle_foreach_command() {
 
 
   string variable_name = words.front();
   string variable_name = words.front();
 
 
-  BlockNesting *nest = new BlockNesting;
-  nest->_state = _in_for ? BS_nested_foreach : BS_foreach;
-  nest->_name = variable_name;
-  nest->_write_state = _write_state;
-  nest->_scope = _scope;
-  nest->_next = _block_nesting;
+  BlockState state = _in_for ? BS_nested_foreach : BS_foreach;
+  BlockNesting *nest = new BlockNesting(state, variable_name);
+  nest->push(this);
 
 
   // We insert in all but the first word in the words vector.
   // We insert in all but the first word in the words vector.
   nest->_words.insert(nest->_words.end(), words.begin() + 1, words.end());
   nest->_words.insert(nest->_words.end(), words.begin() + 1, words.end());
 
 
-  _block_nesting = nest;
-
   if (!_in_for) {
   if (!_in_for) {
     _in_for = true;
     _in_for = true;
     _saved_lines.clear();
     _saved_lines.clear();
@@ -792,17 +866,12 @@ handle_formap_command() {
 
 
   string variable_name = words.front();
   string variable_name = words.front();
 
 
-  BlockNesting *nest = new BlockNesting;
-  nest->_state = _in_for ? BS_nested_formap : BS_formap;
-  nest->_name = words[0];
-  nest->_write_state = _write_state;
-  nest->_scope = _scope;
-  nest->_next = _block_nesting;
+  BlockState state = _in_for ? BS_nested_formap : BS_formap;
+  BlockNesting *nest = new BlockNesting(state, words[0]);
+  nest->push(this);
 
 
   nest->_words.push_back(words[1]);
   nest->_words.push_back(words[1]);
 
 
-  _block_nesting = nest;
-
   if (!_in_for) {
   if (!_in_for) {
     _in_for = true;
     _in_for = true;
     _saved_lines.clear();
     _saved_lines.clear();
@@ -812,27 +881,62 @@ handle_formap_command() {
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-//     Function: PPCommandFile::handle_format_command
+//     Function: PPCommandFile::handle_defsub_command
 //       Access: Protected
 //       Access: Protected
-//  Description: Handles the #format command: change the formatting
-//               mode of lines as they are output.
+//  Description: Handles the #defsub (or #defun) command: save all the
+//               lines between this command and the matching #end as a
+//               callable subroutine to be invoked by a later #call
+//               command.  If is_defsub is false, it means this
+//               subroutine was actually defined via a #defun command,
+//               so it is to be invoked by a later variable reference,
+//               instead of by a #call command.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 bool PPCommandFile::
 bool PPCommandFile::
-handle_format_command() {
-  _params = trim_blanks(_scope->expand_string(_params));
-  if (_params == "straight") {
-    _write_state->_format = WF_straight;
+handle_defsub_command(bool is_defsub) {
+  string command = (is_defsub) ? "#defsub" : "#defun";
 
 
-  } else if (_params == "collapse") {
-    _write_state->_format = WF_collapse;
+  // The first word of the parameter list is the subroutine name; the
+  // rest is the comma-separated list of formal parameter names.
 
 
-  } else if (_params == "makefile") {
-    _write_state->_format = WF_makefile;
+  // Pull off the first word and the rest of the params.
+  size_t p = 0;
+  while (p < _params.length() && !isspace(_params[p])) {
+    p++;
+  }
+  string subroutine_name = trim_blanks(_params.substr(0, p));
 
 
-  } else {
-    cerr << "Ignoring invalid write format: " << _params << "\n";
+  if (subroutine_name.empty()) {
+    cerr << command << " requires at least one parameter.\n";
+    return false;
+  }
+
+  vector<string> formals;
+  _scope->tokenize_params(_params.substr(p), formals, false);
+
+  vector<string>::const_iterator fi;
+  for (fi = formals.begin(); fi != formals.end(); ++fi) {
+    if (!is_valid_formal(*fi)) {
+      cerr << command << " " << subroutine_name
+	   << ": invalid formal parameter name '" << (*fi) << "'\n";
+      return false;
+    }
+  }
+
+  if (_in_for) {
+    cerr << command << " may not appear within another block scoping command like\n"
+	 << "#forscopes, #foreach, #formap, #defsub, or #defun.\n";
+    return false;
   }
   }
 
 
+  BlockState state = is_defsub ? BS_defsub : BS_defun;
+  BlockNesting *nest = new BlockNesting(state, subroutine_name);
+
+  nest->push(this);
+  nest->_words.swap(formals);
+
+  _in_for = true;
+  _saved_lines.clear();
+
   return true;
   return true;
 }
 }
 
 
@@ -853,15 +957,9 @@ handle_output_command() {
     return false;
     return false;
   }
   }
 
 
-  BlockNesting *nest = new BlockNesting;
-  nest->_state = BS_output;
-  nest->_name = words[0];
-  nest->_write_state = _write_state;
-  nest->_scope = _scope;
-  nest->_next = _block_nesting;
+  BlockNesting *nest = new BlockNesting(BS_output, words[0]);
 
 
   // Also check the output flags.
   // Also check the output flags.
-  nest->_flags = 0;
   for (int i = 1; i < (int)words.size(); i++) {
   for (int i = 1; i < (int)words.size(); i++) {
     if (words[i] == "notouch") {
     if (words[i] == "notouch") {
       nest->_flags |= OF_notouch;
       nest->_flags |= OF_notouch;
@@ -870,7 +968,7 @@ handle_output_command() {
     }
     }
   }
   }
 
 
-  _block_nesting = nest;
+  nest->push(this);
 
 
   if (!_in_for) {
   if (!_in_for) {
     string filename = nest->_name;
     string filename = nest->_name;
@@ -918,84 +1016,6 @@ handle_output_command() {
   return true;
   return true;
 }
 }
 
 
-////////////////////////////////////////////////////////////////////
-//     Function: PPCommandFile::handle_print_command
-//       Access: Protected
-//  Description: Handles the #print command: immediately output the
-//               arguments to this line to standard error.
-////////////////////////////////////////////////////////////////////
-bool PPCommandFile::
-handle_print_command() {
-  if (!_in_for) {
-    cerr << _scope->expand_string(_params) << "\n";
-  }
-  return true;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: PPCommandFile::handle_defsub_command
-//       Access: Protected
-//  Description: Handles the #defsub (or #defun) command: save all the
-//               lines between this command and the matching #end as a
-//               callable subroutine to be invoked by a later #call
-//               command.  If is_defsub is false, it means this
-//               subroutine was actually defined via a #defun command,
-//               so it is to be invoked by a later variable reference,
-//               instead of by a #call command.
-////////////////////////////////////////////////////////////////////
-bool PPCommandFile::
-handle_defsub_command(bool is_defsub) {
-  string command = (is_defsub) ? "#defsub" : "#defun";
-
-  // The first word of the parameter list is the subroutine name; the
-  // rest is the comma-separated list of formal parameter names.
-
-  // Pull off the first word and the rest of the params.
-  size_t p = 0;
-  while (p < _params.length() && !isspace(_params[p])) {
-    p++;
-  }
-  string subroutine_name = trim_blanks(_params.substr(0, p));
-
-  if (subroutine_name.empty()) {
-    cerr << command << " requires at least one parameter.\n";
-    return false;
-  }
-
-  vector<string> formals;
-  _scope->tokenize_params(_params.substr(p), formals, false);
-
-  vector<string>::const_iterator fi;
-  for (fi = formals.begin(); fi != formals.end(); ++fi) {
-    if (!is_valid_formal(*fi)) {
-      cerr << command << " " << subroutine_name
-	   << ": invalid formal parameter name '" << (*fi) << "'\n";
-      return false;
-    }
-  }
-
-  if (_in_for) {
-    cerr << command << " may not appear within another block scoping command like\n"
-	 << "#forscopes, #foreach, #formap, #defsub, or #defun.\n";
-    return false;
-  }
-
-  BlockNesting *nest = new BlockNesting;
-  nest->_state = is_defsub ? BS_defsub : BS_defun;
-  nest->_name = subroutine_name;
-  nest->_write_state = _write_state;
-  nest->_scope = _scope;
-  nest->_next = _block_nesting;
-  nest->_words.swap(formals);
-
-  _block_nesting = nest;
-
-  _in_for = true;
-  _saved_lines.clear();
-
-  return true;
-}
-
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: PPCommandFile::handle_end_command
 //     Function: PPCommandFile::handle_end_command
 //       Access: Protected
 //       Access: Protected
@@ -1017,15 +1037,13 @@ handle_end_command() {
   }
   }
 
 
   BlockNesting *nest = _block_nesting;
   BlockNesting *nest = _block_nesting;
+  nest->pop(this);
 
 
-  _scope = nest->_scope;
-  if (_write_state != nest->_write_state) {
-    delete _write_state;
-    _write_state = nest->_write_state;
+  if (nest->_if != _if_nesting) {
+    cerr << "If block not closed within scoping block.\n";
+    return false;
   }
   }
 
 
-  _block_nesting = nest->_next;
-
   if (nest->_state == BS_forscopes) {
   if (nest->_state == BS_forscopes) {
     // Now replay all of the saved lines.
     // Now replay all of the saved lines.
     _in_for = false;
     _in_for = false;
@@ -1091,6 +1109,43 @@ handle_end_command() {
   return true;
   return true;
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: PPCommandFile::handle_format_command
+//       Access: Protected
+//  Description: Handles the #format command: change the formatting
+//               mode of lines as they are output.
+////////////////////////////////////////////////////////////////////
+bool PPCommandFile::
+handle_format_command() {
+  _params = trim_blanks(_scope->expand_string(_params));
+  if (_params == "straight") {
+    _write_state->_format = WF_straight;
+
+  } else if (_params == "collapse") {
+    _write_state->_format = WF_collapse;
+
+  } else if (_params == "makefile") {
+    _write_state->_format = WF_makefile;
+
+  } else {
+    cerr << "Ignoring invalid write format: " << _params << "\n";
+  }
+
+  return true;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PPCommandFile::handle_print_command
+//       Access: Protected
+//  Description: Handles the #print command: immediately output the
+//               arguments to this line to standard error.
+////////////////////////////////////////////////////////////////////
+bool PPCommandFile::
+handle_print_command() {
+  cerr << _scope->expand_string(_params) << "\n";
+  return true;
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: PPCommandFile::handle_include_command
 //     Function: PPCommandFile::handle_include_command
 //       Access: Protected
 //       Access: Protected
@@ -1418,6 +1473,8 @@ include_file(const string &filename) {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 bool PPCommandFile::
 bool PPCommandFile::
 replay_forscopes(const string &name) {
 replay_forscopes(const string &name) {
+  assert(!_in_for);
+
   bool okflag = true;
   bool okflag = true;
 
 
   vector<string> lines;
   vector<string> lines;
@@ -1442,9 +1499,13 @@ replay_forscopes(const string &name) {
     named_scopes->get_scopes(*wi, scopes);
     named_scopes->get_scopes(*wi, scopes);
   }
   }
   PPNamedScopes::sort_by_dependency(scopes);
   PPNamedScopes::sort_by_dependency(scopes);
-    
+
+  // And finally, replay all of the saved lines.
+  BlockNesting *saved_block = _block_nesting;
+  IfNesting *saved_if = _if_nesting;
+
   PPNamedScopes::Scopes::const_iterator si;
   PPNamedScopes::Scopes::const_iterator si;
-  for (si = scopes.begin(); si != scopes.end(); ++si) {
+  for (si = scopes.begin(); si != scopes.end() && okflag; ++si) {
     PPScope::push_scope(_scope);
     PPScope::push_scope(_scope);
     _scope = (*si);
     _scope = (*si);
     
     
@@ -1455,6 +1516,11 @@ replay_forscopes(const string &name) {
     _scope = PPScope::pop_scope();
     _scope = PPScope::pop_scope();
   }
   }
 
 
+  if (saved_block != _block_nesting || saved_if != _if_nesting) {
+    cerr << "Misplaced #end or #endif.\n";
+    okflag = false;
+  }
+
   return okflag;
   return okflag;
 }
 }
 
 
@@ -1466,6 +1532,8 @@ replay_forscopes(const string &name) {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 bool PPCommandFile::
 bool PPCommandFile::
 replay_foreach(const string &varname, const vector<string> &words) {
 replay_foreach(const string &varname, const vector<string> &words) {
+  assert(!_in_for);
+
   bool okflag = true;
   bool okflag = true;
 
 
   vector<string> lines;
   vector<string> lines;
@@ -1477,8 +1545,11 @@ replay_foreach(const string &varname, const vector<string> &words) {
   lines.pop_back();
   lines.pop_back();
 
 
   // Now traverse through the saved words.
   // Now traverse through the saved words.
+  BlockNesting *saved_block = _block_nesting;
+  IfNesting *saved_if = _if_nesting;
+
   vector<string>::const_iterator wi;
   vector<string>::const_iterator wi;
-  for (wi = words.begin(); wi != words.end(); ++wi) {
+  for (wi = words.begin(); wi != words.end() && okflag; ++wi) {
     _scope->define_variable(varname, (*wi));
     _scope->define_variable(varname, (*wi));
     vector<string>::const_iterator li;
     vector<string>::const_iterator li;
     for (li = lines.begin(); li != lines.end() && okflag; ++li) {
     for (li = lines.begin(); li != lines.end() && okflag; ++li) {
@@ -1486,6 +1557,11 @@ replay_foreach(const string &varname, const vector<string> &words) {
     }
     }
   }
   }
 
 
+  if (saved_block != _block_nesting || saved_if != _if_nesting) {
+    cerr << "Misplaced #end or #endif.\n";
+    okflag = false;
+  }
+
   return okflag;
   return okflag;
 }
 }
 
 
@@ -1497,6 +1573,8 @@ replay_foreach(const string &varname, const vector<string> &words) {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 bool PPCommandFile::
 bool PPCommandFile::
 replay_formap(const string &varname, const string &mapvar) {
 replay_formap(const string &varname, const string &mapvar) {
+  assert(!_in_for);
+
   bool okflag = true;
   bool okflag = true;
 
 
   vector<string> lines;
   vector<string> lines;
@@ -1516,6 +1594,9 @@ replay_formap(const string &varname, const string &mapvar) {
   }
   }
 
 
   // Now traverse through the map definition.
   // Now traverse through the map definition.
+  BlockNesting *saved_block = _block_nesting;
+  IfNesting *saved_if = _if_nesting;
+
   PPScope::MapVariableDefinition::const_iterator di;
   PPScope::MapVariableDefinition::const_iterator di;
   for (di = def.begin(); di != def.end() && okflag; ++di) {
   for (di = def.begin(); di != def.end() && okflag; ++di) {
     _scope->define_variable(varname, (*di).first);
     _scope->define_variable(varname, (*di).first);
@@ -1531,6 +1612,11 @@ replay_formap(const string &varname, const string &mapvar) {
     _scope = PPScope::pop_scope();
     _scope = PPScope::pop_scope();
   }
   }
 
 
+  if (saved_block != _block_nesting || saved_if != _if_nesting) {
+    cerr << "Misplaced #end or #endif.\n";
+    okflag = false;
+  }
+
   return okflag;
   return okflag;
 }
 }
 
 

+ 16 - 5
ppremake/ppCommandFile.h

@@ -46,12 +46,12 @@ protected:
   bool handle_forscopes_command();
   bool handle_forscopes_command();
   bool handle_foreach_command();
   bool handle_foreach_command();
   bool handle_formap_command();
   bool handle_formap_command();
-  bool handle_format_command();
-  bool handle_output_command();
-  bool handle_print_command();
   bool handle_defsub_command(bool is_defsub);
   bool handle_defsub_command(bool is_defsub);
+  bool handle_output_command();
   bool handle_end_command();
   bool handle_end_command();
 
 
+  bool handle_format_command();
+  bool handle_print_command();
   bool handle_include_command();
   bool handle_include_command();
   bool handle_sinclude_command();
   bool handle_sinclude_command();
   bool handle_call_command();
   bool handle_call_command();
@@ -85,8 +85,7 @@ private:
   };
   };
 
 
 private:
 private:
-  PPScope *_native_scope;
-  PPScope *_scope;
+  class BlockNesting;
 
 
   enum IfState {
   enum IfState {
     IS_on,   // e.g. a passed #if
     IS_on,   // e.g. a passed #if
@@ -97,7 +96,12 @@ private:
 
 
   class IfNesting {
   class IfNesting {
   public:
   public:
+    IfNesting(IfState state);
+    void push(PPCommandFile *file);
+    void pop(PPCommandFile *file);
+
     IfState _state;
     IfState _state;
+    BlockNesting *_block;
     IfNesting *_next;
     IfNesting *_next;
   };
   };
 
 
@@ -139,8 +143,13 @@ private:
   
   
   class BlockNesting {
   class BlockNesting {
   public:
   public:
+    BlockNesting(BlockState state, const string &name);
+    void push(PPCommandFile *file);
+    void pop(PPCommandFile *file);
+
     BlockState _state;
     BlockState _state;
     string _name;
     string _name;
+    IfNesting *_if;
     WriteState *_write_state;
     WriteState *_write_state;
     PPScope *_scope;
     PPScope *_scope;
     string _true_name;
     string _true_name;
@@ -151,6 +160,8 @@ private:
     BlockNesting *_next;
     BlockNesting *_next;
   };
   };
 
 
+  PPScope *_native_scope;
+  PPScope *_scope;
   bool _got_command;
   bool _got_command;
   bool _in_for;
   bool _in_for;
   IfNesting *_if_nesting;
   IfNesting *_if_nesting;

+ 1 - 0
ppremake/ppScope.cxx

@@ -2658,6 +2658,7 @@ expand_function(const string &funcname,
   if (okflag) {
   if (okflag) {
     okflag = command.end_read();
     okflag = command.end_read();
   }
   }
+  // We don't do anything with okflag here.  What can we do?
 
 
   PPScope::pop_scope();
   PPScope::pop_scope();