|
@@ -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;
|
|
|
}
|
|
}
|
|
|
|
|
|