#include #include #include #include #include #include // #include "../AST.h" #include "int2string.h" #include "streq.h" #include "gputil.h" #include "parameter.h" #include "llist.h" #define DEFAULT_OUTPUT_FILENAME "parameters" static int verbose = 1; /* File to which we write the parameters and their values. */ static char *outfile = DEFAULT_OUTPUT_FILENAME; static ofstream * param_out = NULL; static map param; ///////////////////////////////////////////////////////////////////////////// // Prefixes ///////////////////////////////////////////////////////////////////////////// static llist *prefixes = NULL; static string with_prefix(string p) { for (llist *l = prefixes; l != NULL; l = l->tail()) p = l->front() + '|' + p; return p; } string get_parameter_prefix() { string p; for (llist *l = prefixes; l != NULL; l = l->tail()) p = l->front() + (p.empty() ? p : ('|' + p)); return p; } /* Prefixes we've used already (or are using). */ static set unfresh; static bool is_fresh() { return unfresh.find(with_prefix("")) == unfresh.end(); } static void not_fresh() { unfresh.insert(with_prefix("")); } void push_parameter_prefix(string s, bool must_be_fresh) { prefixes = cons(s, prefixes); if (must_be_fresh) { int count = 1; while (!is_fresh()) { pop_parameter_prefix(); prefixes = cons(s + i2s(count++), prefixes); } } not_fresh(); } string pop_parameter_prefix() { string s = prefixes->front(); prefixes = prefixes->free(); return s; } void set_parameter_prefix(string s, bool must_be_fresh) { while (prefixes != NULL) pop_parameter_prefix(); push_parameter_prefix(s, must_be_fresh); } ////////////////////////////////////////////////////////////////////// // Setting up descriptions of a parameter ////////////////////////////////////////////////////////////////////// static map description; string & parameter_description(string p) { return description[p]; } static void set_output() { if (param_out == NULL) { param_out = new ofstream(outfile); if (param_out == NULL || !*param_out) parameter_error(string("Unable to open output file ") + outfile); } } /* Integer parameters */ static void write_param_in_range(string &p, string &desc, int lo, int hi, int def, int x) { static set written; if (written.find(p) == written.end()) { set_output(); if (verbose > 0 && !desc.empty()) *param_out << '#' << desc << endl; *param_out << p << " (" << i2s(lo) << " to " << i2s(hi) << "): " << x << endl; if (verbose > 1 && x != lo) *param_out << "# default was " << def << endl; if (verbose > 0) *param_out << endl; param_out->flush(); written.insert(p); } } /* Return a value between lo and hi, inclusive. lo is the default. */ int get_parameter_in_range(string p, string desc, int lo, int hi, bool write) { static set written; p = with_prefix(p); map::iterator i = param.find(p); int x = (i == param.end()) ? lo : (*i).second; if (x < lo) { parameter_warn(p, string("specified to be ") + i2s(x) + ", but must be between " + i2s(lo) + " and " + i2s(hi) + "." " Using " + i2s(lo) + " instead."); x = lo; } else if (x > hi) { parameter_warn(p, string("specified to be ") + i2s(x) + ", but must be between " + i2s(lo) + " and " + i2s(hi) + "." " Using " + i2s(hi) + " instead."); x = hi; } if (write) write_param_in_range(p, desc, lo, hi, lo, x); return x; } /* Return a value between lo and hi, inclusive. def is the default. */ int get_parameter_in_range(string p, string desc, int lo, int hi, int def, bool write) { static set written; p = with_prefix(p); map::iterator i = param.find(p); int x = (i == param.end()) ? def : (*i).second; if (x < lo) { parameter_warn(p, string("specified to be ") + i2s(x) + ", but must be between " + i2s(lo) + " and " + i2s(hi) + "." " Using " + i2s(lo) + " instead."); x = lo; } else if (x > hi) { parameter_warn(p, string("specified to be ") + i2s(x) + ", but must be between " + i2s(lo) + " and " + i2s(hi) + "." " Using " + i2s(hi) + " instead."); x = hi; } if (write) write_param_in_range(p, desc, lo, hi, def, x); return x; } int get_parameter(string p, int kind) { return get_parameter(p, parameter_description(p), kind); } int get_parameter(string p, string desc, int kind, int def, bool write) { return get_parameter_without_prefix(with_prefix(p), desc, kind, def, write); } int get_parameter_without_prefix(string p, int kind, bool write) { return get_parameter_without_prefix(p, parameter_description(p), kind, write); } int get_parameter_without_prefix(string p, string desc, int kind, int def, bool write) { static set written; map::iterator i = param.find(p); int x = (i == param.end()) ? def : (*i).second; if (kind == NONNEG && x < 0) { parameter_warn(p, string("specified to be ") + i2s(x) + ", but must be non-negative. Using 0 instead."); x = 0; } if (kind == BOOL && x != 0 && x != 1) { parameter_warn(p, string("specified to be ") + i2s(x) + ", but is a boolean value. Using 1 instead."); x = 1; } if (write && written.find(p) == written.end()) { set_output(); if (verbose > 0 && !desc.empty()) *param_out << '#' << desc << endl; *param_out << p << (kind == NONNEG ? " (unsigned)" : (kind == NORMAL ? "" : " (bool)")) << ": " << x << endl; if (verbose > 1 && x != def) *param_out << "# default was " << def << endl; if (verbose > 0) *param_out << endl; param_out->flush(); written.insert(p); } return x; } /* Boolean parameters */ /* d is the default */ bool get_bool_parameter(string p, bool d) { return get_bool_parameter(p, parameter_description(p), d); } bool get_bool_parameter(string p, string desc, bool d) { return get_bool_parameter_without_prefix(with_prefix(p), desc, d); } bool get_bool_parameter_without_prefix(string p, bool d) { return get_bool_parameter_without_prefix(p, parameter_description(p), d); } bool get_bool_parameter_without_prefix(string p, string desc, bool d, bool write) { return get_parameter_without_prefix(p, desc, BOOL, (d ? 1 : 0), write) != 0; } ///////////////////////////////////////////////////////////////////////////// void parameter_warn(string p, string warning) { cerr << "Warning for parameter `" << p << "': " << warning << endl; } void parameter_error(string error, bool fatal) { cerr << "Error: " << error << endl; if (fatal) exit(-5); } ///////////////////////////////////////////////////////////////////////////// // Parsing parameters and command-line arguments ///////////////////////////////////////////////////////////////////////////// /* Record a (parameter, value) pair. The value must be an integer. */ static void parameter_pair(char *p, char *v) { v = trim(v); if (v[0] == '\0') v = "0"; if (!(is_all_digits(v) || v[0] == '-' && is_all_digits(v + 1))) parameter_error(string("Parameter `") + p + "' specified to have non-integer value `" + v + "'"); int i; sscanf(v, "%d", &i); int c = strlen(p); char *s = new char [c + 1]; strcpy(s, p); if (c > 0 && s[c - 1] == ')') for (int i = 0; i < c - 2; i++) if (s[i] == ' ' && s[i + 1] == '(') { s[i] = '\0'; break; } // cout << "param " << s << ": " << i << endl; param[string(s)] = i; delete s; } /* Read parameters from a file. Ignore lines that are blank or that start with '#'. Other lines are assumed to be of the form "p: v" or "p (...): v" where v is an integer. (In the second case everything in from the space before the first paren to the last paren is ignored.) Abort if the data are malformed or the file can't be opened. */ static void parameter_parse_args_from_file(char *filename) { map param_set_on_line; cout << "Attempting to read params from " << filename << endl; ifstream f(filename); if (!f) parameter_error(string("Unable to open file ") + filename); int lineno = 0; int n = 999; while (n > 0) { char *s = readline(f, &n); lineno++; if (n > 0 && s[0] != '#' && !is_all_whitespace(s)) { int c = findlast(':', s, n); if (c < 0) parameter_error("No colon in line " + i2s(lineno) + " of file " + filename); s[c] = '\0'; if (param_set_on_line[s] != 0) parameter_warn(s, "Setting on line " + i2s(lineno) + " overrides setting on line " + i2s(param_set_on_line[s])); param_set_on_line[s] = lineno; parameter_pair(s, s + c + 1); } delete[] s; } } static void parameter_parse_args_from_list(char **l, int n) { while (n >= 2) { cout << "Command-line param: " << l[0] << ": " << l[1] << endl; parameter_pair(l[0], l[1]); n -= 2; l += 2; } if (n != 0) { assert(n == 1); cerr << "Error parsing parameters: `" << l[0] << "' is unmatched" << endl; exit(-9); } } /* Find arguments between the first +++ and the first --- after that, and parse them pairwise (parameter, value). Leave argc and argv such that the parameters parsed no longer appear. Abort if there is an error. Do nothing if there is no +++ eventually followed by a ---. */ static void parameter_parse_args2(int &argc, char **argv) { // showargs(argc, argv); int start = -1, end = -1; for (int i = 0; i < argc; i++) if (streq(argv[i], "+++")) { start = i; break; } if (start < 0) return; for (int i = start + 1; i < argc; i++) if (streq(argv[i], "---")) { end = i; break; } if (end < 0) return; parameter_parse_args_from_list(argv + start + 1, end - start - 1); remove_args(argc, argv, start, end); // showargs(argc, argv); } /* Handle the following arguments and strip them out of argc/argv: -pi -po -poverbose +++ ... --- There can be any number of occurences of "-pi "; there can only be one +++ ... --- section. All the above are processed left to right. The rightmost -po argument, if any, specifies the output filename for parameters. The rightmost -poverbose argument, if any, specifies the level of verbosity in the output file. */ void parameter_parse_args(int &argc, char **argv) { char *infile; int start = -1, end = -1; for (int i = 0; i < argc; i++) if (streq(argv[i], "+++")) { start = i; break; } if (start > 0) for (int i = start + 1; i < argc; i++) if (streq(argv[i], "---")) { end = i; break; } /* At this point, start and end index the +++ and --- that bracket parameters that we shall parse later. Or, if one or both is negative, then there is no +++ and --- pair. */ /* Handle any "-pi foo" before start, then the +++ ... --- pair. */ if (end > 0) { while (start > 0 && snaffle_from_args("-pi", infile, argc, argv, start)) { start -= 2; parameter_parse_args_from_file(infile); } parameter_parse_args2(argc, argv); } /* +++ ... --- has been handled, so now look for any occurence of "-pi foo" or "-po foo" or "-poverbose n". */ while (snaffle_from_args("-pi", infile, argc, argv)) parameter_parse_args_from_file(infile); while (snaffle_from_args("-po", outfile, argc, argv)) ; char *temp; while (snaffle_from_args("-poverbose", temp, argc, argv)) sscanf(temp, "%d", &verbose); }