git-svn-id: svn://svn.icms.temple.edu/lammps-ro/trunk@5258 f3b2605a-c512-4ea7-a41b-209d697bcdaa

This commit is contained in:
sjplimp
2010-11-18 17:28:47 +00:00
parent 37b51e682f
commit 31e65b4e72
3 changed files with 303 additions and 95 deletions

View File

@ -265,7 +265,7 @@ char *Input::one(const char *single)
command = first word
narg = # of args
arg[] = individual args
treat text between double quotes as one arg
treat text between single/double quotes as one arg
------------------------------------------------------------------------- */
void Input::parse()
@ -275,19 +275,17 @@ void Input::parse()
strcpy(copy,line);
// strip any # comment by resetting string terminator
// do not strip # inside double quotes
// do not strip # inside single/double quotes
int level = 0;
char quote = '\0';
char *ptr = copy;
while (*ptr) {
if (*ptr == '#' && level == 0) {
if (*ptr == '#' && !quote) {
*ptr = '\0';
break;
}
if (*ptr == '"') {
if (level == 0) level = 1;
else level = 0;
}
if (*ptr == quote) quote = '\0';
else if (*ptr == '"' || *ptr == '\'') quote = *ptr;
ptr++;
}
@ -302,9 +300,12 @@ void Input::parse()
if (command == NULL) return;
// point arg[] at each subsequent arg
// treat text between double quotes as one arg
// treat text between single/double quotes as one arg
// insert string terminators in copy to delimit args
quote = '\0';
int iarg,argstart;
narg = 0;
while (1) {
if (narg == maxarg) {
@ -312,19 +313,23 @@ void Input::parse()
arg = (char **) memory->srealloc(arg,maxarg*sizeof(char *),"input:arg");
}
arg[narg] = strtok(NULL," \t\n\r\f");
if (arg[narg] && arg[narg][0] == '\"') {
if (!arg[narg]) break;
if (!quote && (arg[narg][0] == '"' || arg[narg][0] == '\'')) {
quote = arg[narg][0];
argstart = narg;
arg[narg] = &arg[narg][1];
if (arg[narg][strlen(arg[narg])-1] == '\"')
}
if (quote && arg[narg][strlen(arg[narg])-1] == quote) {
for (iarg = argstart; iarg < narg; iarg++)
arg[iarg][strlen(arg[iarg])] = ' ';
arg[narg][strlen(arg[narg])-1] = '\0';
else {
arg[narg][strlen(arg[narg])] = ' ';
ptr = strtok(arg[narg],"\"");
if (ptr == NULL) error->all("Unbalanced quotes in input line");
narg = argstart;
quote = '\0';
}
narg++;
}
if (arg[narg]) narg++;
else break;
}
if (quote) error->all("Unbalanced quotes in input line");
}
/* ----------------------------------------------------------------------
@ -335,18 +340,18 @@ void Input::parse()
void Input::substitute(char *str, int flag)
{
// use work[] as scratch space to expand str
// do not replace $ inside double quotes as flagged by level
// do not replace $ inside single/double quotes
// var = pts at variable name, ended by NULL
// if $ is followed by '{', trailing '}' becomes NULL
// else $x becomes x followed by NULL
// beyond = pts at text following variable
char *var,*value,*beyond;
int level = 0;
char quote = '\0';
char *ptr = str;
while (*ptr) {
if (*ptr == '$' && level == 0) {
if (*ptr == '$' && !quote) {
if (*(ptr+1) == '{') {
var = ptr+2;
int i = 0;
@ -379,10 +384,8 @@ void Input::substitute(char *str, int flag)
}
continue;
}
if (*ptr == '"') {
if (level == 0) level = 1;
else level = 0;
}
if (*ptr == quote) quote = '\0';
else if (*ptr == '"' || *ptr == '\'') quote = *ptr;
ptr++;
}
}
@ -521,52 +524,84 @@ void Input::echo()
void Input::ifthenelse()
{
if (narg < 5) error->all("Illegal if command");
if (narg < 4) error->all("Illegal if command");
// flag = 0 for "then"
// flag = 1 for "else"
// substitute for variables in Boolean expression for "if"
// in case expression was enclosed in quotes
int flag = 0;
if (strcmp(arg[1],"==") == 0) {
if (atof(arg[0]) == atof(arg[2])) flag = 1;
} else if (strcmp(arg[1],"!=") == 0) {
if (atof(arg[0]) != atof(arg[2])) flag = 1;
} else if (strcmp(arg[1],"<") == 0) {
if (atof(arg[0]) < atof(arg[2])) flag = 1;
} else if (strcmp(arg[1],"<=") == 0) {
if (atof(arg[0]) <= atof(arg[2])) flag = 1;
} else if (strcmp(arg[1],">") == 0) {
if (atof(arg[0]) > atof(arg[2])) flag = 1;
} else if (strcmp(arg[1],">=") == 0) {
if (atof(arg[0]) >= atof(arg[2])) flag = 1;
} else error->all("Illegal if command");
substitute(arg[0],0);
// first = arg index of first "then" or "else" command
// last = arg index of last "then" or "else" command
// evaluate Boolean expression for "if"
int iarg,first,last;
double btest = variable->evaluate_boolean(arg[0]);
// identify range of commands within arg list for then or else
// for else, if no comands, just return
// bound "then" commands
if (strcmp(arg[3],"then") != 0) error->all("Illegal if command");
if (flag) {
iarg = first = 4;
while (iarg < narg && strcmp(arg[iarg],"else") != 0) iarg++;
last = iarg-1;
} else {
iarg = 4;
while (iarg < narg && strcmp(arg[iarg],"else") != 0) iarg++;
if (iarg == narg) return;
first = iarg+1;
last = narg-1;
}
if (strcmp(arg[1],"then") != 0) error->all("Illegal if command");
int first = 2;
int iarg = first;
while (iarg < narg &&
(strcmp(arg[iarg],"elif") != 0 && strcmp(arg[iarg],"else") != 0))
iarg++;
int last = iarg-1;
// execute "then" commands
// make copies of all arg string commands
// required because re-parsing a command via one() will wipe out args
if (btest != 0.0) {
int ncommands = last-first + 1;
if (ncommands <= 0) error->all("Illegal if command");
// make copies of arg strings that are commands
// required because re-parsing commands via one() will wipe out args
char **commands = new char*[ncommands];
ncommands = 0;
for (int i = first; i <= last; i++) {
int n = strlen(arg[i]) + 1;
if (n == 1) error->all("Illegal if command");
commands[ncommands] = new char[n];
strcpy(commands[ncommands],arg[i]);
ncommands++;
}
for (int i = 0; i < ncommands; i++)
char *command = input->one(commands[i]);
for (int i = 0; i < ncommands; i++) delete [] commands[i];
delete [] commands;
return;
}
// done if no "elif" or "else"
if (iarg == narg) return;
// check "elif" or "else" until find commands to execute
// substitute for variables and evaluate Boolean expression for "elif"
// bound and execute "elif" or "else" commands
while (1) {
if (iarg+2 > narg) error->all("Illegal if command");
if (strcmp(arg[iarg],"elif") == 0) {
substitute(arg[iarg+1],0);
btest = variable->evaluate_boolean(arg[iarg+1]);
first = iarg+2;
} else {
btest = 1.0;
first = iarg+1;
}
iarg = first;
while (iarg < narg &&
(strcmp(arg[iarg],"elif") != 0 && strcmp(arg[iarg],"else") != 0))
iarg++;
last = iarg-1;
if (btest == 0.0) continue;
int ncommands = last-first + 1;
if (ncommands <= 0) error->all("Illegal if command");
char **commands = new char*[ncommands];
ncommands = 0;
@ -587,6 +622,9 @@ void Input::ifthenelse()
for (int i = 0; i < ncommands; i++) delete [] commands[i];
delete [] commands;
return;
}
}
/* ---------------------------------------------------------------------- */
@ -685,17 +723,14 @@ void Input::next_command()
void Input::print()
{
if (narg == 0) error->all("Illegal print command");
if (narg != 1) error->all("Illegal print command");
// substitute for $ variables (no printing)
// print args one at a time, separated by spaces
// substitute for $ variables (no printing) and print arg
for (int i = 0; i < narg; i++) {
substitute(arg[i],0);
substitute(arg[0],0);
if (me == 0) {
if (screen) fprintf(screen,"%s ",arg[i]);
if (logfile) fprintf(logfile,"%s ",arg[i]);
}
if (screen) fprintf(screen,"%s ",arg[0]);
if (logfile) fprintf(logfile,"%s ",arg[0]);
}
if (me == 0) {

View File

@ -608,7 +608,7 @@ void Variable::copy(int narg, char **from, char **to)
constant = PI
thermo keyword = ke, vol, atoms, ...
math operation = (),-x,x+y,x-y,x*y,x/y,x^y,
x==y,x!=y,x<y,x<=y,x>y,x>=y,
x==y,x!=y,x<y,x<=y,x>y,x>=y,x&&y,x||y,
sqrt(x),exp(x),ln(x),log(x),
sin(x),cos(x),tan(x),asin(x),atan2(y,x),...
group function = count(group), mass(group), xcm(group,x), ...
@ -3069,3 +3069,175 @@ void Variable::print_tree(Tree *tree, int level)
if (tree->right) print_tree(tree->right,level+1);
return;
}
/* ----------------------------------------------------------------------
recursive evaluation of string str
called from "if" command in input script
str is a boolean expression containing one or more items:
number = 0.0, -5.45, 2.8e-4, ...
math operation = (),x==y,x!=y,x<y,x<=y,x>y,x>=y,x&&y,x||y
------------------------------------------------------------------------- */
double Variable::evaluate_boolean(char *str)
{
int op,opprevious;
double value1,value2;
char onechar;
char *ptr;
double argstack[MAXLEVEL];
int opstack[MAXLEVEL];
int nargstack = 0;
int nopstack = 0;
int i = 0;
int expect = ARG;
while (1) {
onechar = str[i];
// whitespace: just skip
if (isspace(onechar)) i++;
// ----------------
// parentheses: recursively evaluate contents of parens
// ----------------
else if (onechar == '(') {
if (expect == OP) error->all("Invalid Boolean syntax in if command");
expect = OP;
char *contents;
i = find_matching_paren(str,i,contents);
i++;
// evaluate contents and push on stack
argstack[nargstack++] = evaluate_boolean(contents);
delete [] contents;
// ----------------
// number: push value onto stack
// ----------------
} else if (isdigit(onechar) || onechar == '.') {
if (expect == OP) error->all("Invalid Boolean syntax in if command");
expect = OP;
// istop = end of number, including scientific notation
int istart = i;
while (isdigit(str[i]) || str[i] == '.') i++;
if (str[i] == 'e' || str[i] == 'E') {
i++;
if (str[i] == '+' || str[i] == '-') i++;
while (isdigit(str[i])) i++;
}
int istop = i - 1;
int n = istop - istart + 1;
char *number = new char[n+1];
strncpy(number,&str[istart],n);
number[n] = '\0';
argstack[nargstack++] = atof(number);
delete [] number;
// ----------------
// Boolean operator, including end-of-string
// ----------------
} else if (strchr("<>=!&|\0",onechar)) {
if (onechar == '=') {
if (str[i+1] != '=')
error->all("Invalid Boolean syntax in if command");
op = EQ;
i++;
} else if (onechar == '!') {
if (str[i+1] != '=')
error->all("Invalid Boolean syntax in if command");
op = NE;
i++;
} else if (onechar == '<') {
if (str[i+1] != '=') op = LT;
else {
op = LE;
i++;
}
} else if (onechar == '>') {
if (str[i+1] != '=') op = GT;
else {
op = GE;
i++;
}
} else if (onechar == '&') {
if (str[i+1] != '&')
error->all("Invalid Boolean syntax in if command");
op = AND;
i++;
} else if (onechar == '|') {
if (str[i+1] != '|')
error->all("Invalid Boolean syntax in if command");
op = OR;
i++;
} else op = DONE;
i++;
if (expect == ARG) error->all("Invalid Boolean syntax in if command");
expect = ARG;
// evaluate stack as deep as possible while respecting precedence
// before pushing current op onto stack
while (nopstack && precedence[opstack[nopstack-1]] >= precedence[op]) {
opprevious = opstack[--nopstack];
value2 = argstack[--nargstack];
value1 = argstack[--nargstack];
if (opprevious == EQ) {
if (value1 == value2) argstack[nargstack++] = 1.0;
else argstack[nargstack++] = 0.0;
} else if (opprevious == NE) {
if (value1 != value2) argstack[nargstack++] = 1.0;
else argstack[nargstack++] = 0.0;
} else if (opprevious == LT) {
if (value1 < value2) argstack[nargstack++] = 1.0;
else argstack[nargstack++] = 0.0;
} else if (opprevious == LE) {
if (value1 <= value2) argstack[nargstack++] = 1.0;
else argstack[nargstack++] = 0.0;
} else if (opprevious == GT) {
if (value1 > value2) argstack[nargstack++] = 1.0;
else argstack[nargstack++] = 0.0;
} else if (opprevious == GE) {
if (value1 >= value2) argstack[nargstack++] = 1.0;
else argstack[nargstack++] = 0.0;
} else if (opprevious == AND) {
if (value1 != 0.0 && value2 != 0.0) argstack[nargstack++] = 1.0;
else argstack[nargstack++] = 0.0;
} else if (opprevious == OR) {
if (value1 != 0.0 || value2 != 0.0) argstack[nargstack++] = 1.0;
else argstack[nargstack++] = 0.0;
}
}
// if end-of-string, break out of entire formula evaluation loop
if (op == DONE) break;
// push current operation onto stack
opstack[nopstack++] = op;
} else error->all("Invalid Boolean syntax in if command");
}
if (nopstack) error->all("Invalid Boolean syntax in if command");
if (nargstack != 1) error->all("Invalid Boolean syntax in if command");
return argstack[0];
}

View File

@ -32,6 +32,7 @@ class Variable : protected Pointers {
double compute_equal(int);
void compute_atom(int, int, double *, int, int);
int int_between_brackets(char *&);
double evaluate_boolean(char *);
private:
int me;