copy
#include <iostream>
#include <fstream>
#include <vector>
#include <string>
#include <sstream>
#include <iomanip>
#include <map>
#include <algorithm>
#include <cctype> // For std::isspace
#include <cstdlib> // For std::system()
#include <omp.h>
using namespace std;
class SavitarInterpreter {
public:
maps<string, string> variables;
// Helper function to check if a string is a number
bool isNumber(const string& s) {
return !s.empty() && all_of(s.begin(), s.end(), ::isdigit);
}
// Left-pad with zeros based on @ syntax
string padLeft(const string& value, int length) {
stringstream ss;
ss << setw(length) << setfill('0') << value;
return ss.str();
}
// Generate an array from start:step:end and pad each element to the specified length
vector<string>generatePaddedArray(int start, int step, int end, int length) {
vector<string>result;
for (int i = start; i <= end; i += step) {
result.push_back(padLeft(to_string(i), length));
}
return result;
}
// Split a string by a delimiter
vector<string>split(const string& s, char delimiter) {
vector<string>tokens;
string token;
stringstream ss(s);
while (getline(ss, token, delimiter)) {
tokens.push_back(token);
}
return tokens;
}
// Helper function to trim spaces (only for spaces outside of quotes)
string trim(const string& str) {
size_t first = str.find_first_not_of(' ');
size_t last = str.find_last_not_of(' ');
if (first == string::npos || last == string::npos) return "";
return str.substr(first, (last - first + 1));
}
// Helper function to check if a string is quoted
bool isQuoted(const string& s) {
return s.front() == '"' && s.back() == '"';
}
// Remove the surrounding quotes from a string if it's quoted
string removeQuotes(const string& s) {
if (isQuoted(s)) {
return s.substr(1, s.length() - 2); // Remove the quotes
}
return s;
}
void assignVariable(const string& expression) {
string trimmedExpression = trim(expression); // 去除两端的空白字符
size_t eqPos = trimmedExpression.find('=');
if (eqPos == string::npos) {
cerr << "Invalid assignment expression: " << expression << endl;
return;
}
string name = trimmedExpression.substr(0, eqPos);
string value = trimmedExpression.substr(eqPos + 1);
// 处理带引号的字符串(支持空格和特殊字符)
value = trim(value); // 去除值两端的空格
if (isQuoted(value)) {
// 如果是引号包围的字符串,去掉引号并赋值
variables[name] = removeQuotes(value); // 只赋值引号中的内容
return;
}
// 处理数组访问或切片
size_t leftBracket = value.find('[');
size_t rightBracket = value.find(']');
if (leftBracket != string::npos && rightBracket != string::npos && leftBracket < rightBracket) {
string arrayName = value.substr(0, leftBracket);
string indexOrRange = value.substr(leftBracket + 1, rightBracket - leftBracket - 1);
if (variables.find(arrayName) == variables.end()) {
cerr << "Variable not found: " << arrayName << endl;
return;
}
vector<string>array = split(variables[arrayName], ',');
// Element access
if (isNumber(indexOrRange)) {
int index = stoi(indexOrRange);
if (index < 0 || index >= static_cast<int>(array.size())) {
cerr << "Index out of bounds: " << index << endl;
return;
}
variables[name] = array[index];
}
// Slicing
else {
vector<string>rangeParts = split(indexOrRange, ':');
if (rangeParts.size() != 2 || !isNumber(rangeParts[0]) || !isNumber(rangeParts[1])) {
cerr << "Invalid slicing range: " << indexOrRange << endl;
return;
}
int start = stoi(rangeParts[0]);
int end = stoi(rangeParts[1]);
if (start < 0 || end >= static_cast<int>(array.size()) || start > end) {
cerr << "Invalid slicing indices." << endl;
return;
}
stringstream ss;
for (int i = start; i <= end; ++i) {
if (i > start) ss << ",";
ss << array[i];
}
variables[name] = ss.str();
}
return;
}
// Check if the value contains '@'
size_t atPos = value.find('@');
if (atPos != string::npos) {
// Extract padding length and actual value
string paddingLengthStr = value.substr(0, atPos);
string remainingValue = value.substr(atPos + 1);
// Check if the remaining value is an array definition
if (remainingValue.find(':') != string::npos) {
defineArrayVariable(name, remainingValue, stoi(paddingLengthStr));
} else {
// Otherwise, it's a single value with padding
if (!isNumber(paddingLengthStr)) {
cerr << "Invalid padding length: " << paddingLengthStr << endl;
return;
}
int paddingLength = stoi(paddingLengthStr);
variables[name] = padLeft(remainingValue, paddingLength);
}
} else {
// Check if the value is an array definition
if (value.find(':') != string::npos) {
defineArrayVariable(name, value);
} else {
// Assign variable as-is
variables[name] = value;
}
}
}
void defineArrayVariable(const string& name, const string& range, int length = -1) {
vector<string>parts = split(range, ':');
if (parts.size() < 2 || parts.size() > 3) {
cerr << "Invalid range format for variable: " << name << endl;
return;
}
if (!isNumber(parts[0]) || !isNumber(parts.back())) {
cerr << "Invalid range values for variable: " << name << endl;
return;
}
int start = stoi(parts[0]);
int step = 1; // Default step
int end = stoi(parts.back());
if (parts.size() == 3) {
if (!isNumber(parts[1])) {
cerr << "Invalid step value for variable: " << name << endl;
return;
}
step = stoi(parts[1]);
}
vector<string>array;
if (length != -1) {
array = generatePaddedArray(start, step, end, length);
} else {
array = generatePaddedArray(start, step, end, 0); // No padding if no length specified
}
stringstream ss;
for (size_t i = 0; i < array.size(); ++i) {
if (i > 0) ss << ",";
ss << array[i];
}
variables[name] = ss.str();
}
void concatenateVariables(const string& expression) {
size_t eqPos = expression.find('=');
size_t plusPos = expression.find('+');
if (eqPos == string::npos || plusPos == string::npos || plusPos < eqPos) {
cerr << "Invalid concatenation expression: " << expression << endl;
return;
}
string resultName = expression.substr(0, eqPos);
string var1 = expression.substr(eqPos + 1, plusPos - eqPos - 1);
string var2 = expression.substr(plusPos + 1);
// Trim whitespace from variable names
var1 = trim(var1);
var2 = trim(var2);
// Determine if var1 and var2 are arrays or strings
bool isVar1Array = false;
bool isVar2Array = false;
if (variables.find(var1) != variables.end()) {
if (variables[var1].find(',') != string::npos) {
isVar1Array = true;
}
} else {
cerr << "First variable not found: " << var1 << endl;
return;
}
if (variables.find(var2) != variables.end()) {
if (variables[var2].find(',') != string::npos) {
isVar2Array = true;
}
} else {
cerr << "Second variable not found: " << var2 << endl;
return;
}
if (isVar1Array && isVar2Array) {
// Both are arrays, concatenate element-wise if they have the same length
vector<string>array1 = split(variables[var1], ',');
vector<string>array2 = split(variables[var2], ',');
if (array1.size() != array2.size()) {
cerr << "Arrays must be of the same length for element-wise concatenation." << endl;
return;
}
vector<string>result;
for (size_t i = 0; i < array1.size(); ++i) {
result.push_back(array1[i] + array2[i]);
}
stringstream ss;
for (size_t i = 0; i < result.size(); ++i) {
if (i > 0) ss << ",";
ss << result[i];
}
variables[resultName] = ss.str(); // Store the result
} else if (isVar1Array) {
// var1 is an array, var2 is a string
vector<string>array1 = split(variables[var1], ',');
string strVar2 = variables[var2];
vector<string>result;
for (const auto& elem : array1) {
result.push_back(elem + strVar2);
}
stringstream ss;
for (size_t i = 0; i < result.size(); ++i) {
if (i > 0) ss << ",";
ss << result[i];
}
variables[resultName] = ss.str(); // Store the result
} else if (isVar2Array) {
// var1 is a string, var2 is an array
string strVar1 = variables[var1];
vector<string>array2 = split(variables[var2], ',');
vector<string>result;
for (const auto& elem : array2) {
result.push_back(strVar1 + elem);
}
stringstream ss;
for (size_t i = 0; i < result.size(); ++i) {
if (i > 0) ss << ",";
ss << result[i];
}
variables[resultName] = ss.str(); // Store the result
} else {
// Both are strings, simple concatenation
string strVar1 = variables[var1];
string strVar2 = variables[var2];
variables[resultName] = strVar1 + strVar2;
}
}
void printVariable(const string& command) {
size_t spacePos = command.find(' ');
if (spacePos == string::npos || command.substr(0, spacePos) != "print") {
cerr << "Invalid print command: " << command << endl;
return;
}
string name = command.substr(spacePos + 1); // Extract variable name after "print "
name.erase(remove_if(name.begin(), name.end(), [](unsigned char c){ return std::isspace(c); }), name.end()); // Remove extra spaces
if (variables.find(name) != variables.end()) {
cout << name << " = " << variables[name] << endl;
} else {
cerr << "Variable not found: " << name << endl;
}
}
// Execute system commands from variables (exec function)
void execCommand(const string& command) {
size_t spacePos = command.find(' ');
if (spacePos == string::npos || command.substr(0, spacePos) != "exec") {
cerr << "Invalid exec command: " << command << endl;
return;
}
string varName = command.substr(spacePos + 1);
varName.erase(remove_if(varName.begin(), varName.end(), [](unsigned char c){ return std::isspace(c); }), varName.end());
if (variables.find(varName) != variables.end()) {
string value = variables[varName];
vector<string>commands = split(value, ','); // Split the command string if it's an array
#pragma omp parallel for
for (size_t i = 0; i < commands.size(); ++i)
{
int result = std::system(commands[i].c_str());
if (result != 0) {
cerr << "Command failed: " << commands[i] << endl;
}
}
} else {
cerr << "Variable not found: " << varName << endl;
}
}
void executeFromFile(const string& filename) {
ifstream file(filename);
if (!file.is_open()) {
cerr << "Could not open file: " << filename << endl;
return;
}
string line;
while (getline(file, line)) {
// Ignore empty lines and comments
line = line.substr(0, line.find('#')); // Remove comments
if (line.empty()) {
continue;
}
// Check for print, exec, and assignment
if (line.find("print") == 0) {
printVariable(line);
} else if (line.find("exec") == 0) {
execCommand(line); // Handle exec command
} else if (line.find("+") != string::npos) {
concatenateVariables(line);
} else {
assignVariable(line);
}
}
file.close();
}
};
int main(int argc, char *argv[]) {
if(argc>1)
{
int numThreads = omp_get_num_procs();
if(argc==3)
numThreads=atoi(argv[2]);
omp_set_num_threads(numThreads);
SavitarInterpreter interpreter;
interpreter.executeFromFile(argv[1]);
}
else cout<<"Please specify the Savitar script."<<endl;
return 0;
}