mirror of
https://github.com/Theaninova/BeatLanguageMapper.git
synced 2025-12-10 21:46:16 +00:00
Added untested code for interpreting bml
This commit is contained in:
288
Source/MediocreMapper/BeatLanguage.cpp
Normal file
288
Source/MediocreMapper/BeatLanguage.cpp
Normal file
@@ -0,0 +1,288 @@
|
|||||||
|
#include "BeatMapLanInterpreter.h"
|
||||||
|
|
||||||
|
BeatMapLanInterpreter::BeatMapLanInterpreter(extFuns functions)
|
||||||
|
{
|
||||||
|
externalFunctions = functions;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
BeatMapLanInterpreter::~BeatMapLanInterpreter()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void BeatMapLanInterpreter::interpret(string code)
|
||||||
|
{
|
||||||
|
pos = 0;
|
||||||
|
bmlCode = code;
|
||||||
|
|
||||||
|
while (pos < bmlCode.length)
|
||||||
|
{
|
||||||
|
if (bmlCode[pos] == key_fun)
|
||||||
|
{
|
||||||
|
pos++;
|
||||||
|
|
||||||
|
string fun_type = pop_next(' ');
|
||||||
|
|
||||||
|
jumpSpaces();
|
||||||
|
|
||||||
|
if (fun_type.compare(fun_type_function))
|
||||||
|
{
|
||||||
|
string function_name = pop_next(' ');
|
||||||
|
functions.push_back({ function_name, pos });
|
||||||
|
gotoNext(key_block_closing_bracket);
|
||||||
|
}
|
||||||
|
else if (fun_type.compare(fun_type_main))
|
||||||
|
{
|
||||||
|
executeFun(pos, vector<string>(), vector<string>());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (code[pos] == key_comment)
|
||||||
|
{
|
||||||
|
pos++;
|
||||||
|
gotoNext(key_comment);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
pos++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
string BeatMapLanInterpreter::pop_next(char escape_char)
|
||||||
|
{
|
||||||
|
string builder;
|
||||||
|
bool variable = false;
|
||||||
|
|
||||||
|
if (bmlCode[pos] == key_variable) {
|
||||||
|
pos++;
|
||||||
|
variable = true;
|
||||||
|
}
|
||||||
|
else if (bmlCode[pos] == key_math_opening_bracket) {
|
||||||
|
pos++;
|
||||||
|
return evalMathExpression();
|
||||||
|
}
|
||||||
|
else if (bmlCode[pos] == key_request_return) {
|
||||||
|
pos++;
|
||||||
|
string fun_name = pop_next(' ');
|
||||||
|
gotoNext(key_block_opening_bracket);
|
||||||
|
return callFunction(fun_name, popArgs());
|
||||||
|
}
|
||||||
|
|
||||||
|
while (bmlCode[pos] != escape_char)
|
||||||
|
{
|
||||||
|
if (bmlCode[pos] == key_section_marker)
|
||||||
|
{
|
||||||
|
while (bmlCode[pos] != key_section_marker)
|
||||||
|
{
|
||||||
|
builder.push_back(bmlCode[pos]);
|
||||||
|
pos++;
|
||||||
|
}
|
||||||
|
pos++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
builder.push_back(bmlCode[pos]);
|
||||||
|
pos++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pos++;
|
||||||
|
|
||||||
|
if (variable)
|
||||||
|
{
|
||||||
|
return getVarVal(builder);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return builder;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void BeatMapLanInterpreter::gotoNext(char key)
|
||||||
|
{
|
||||||
|
while (bmlCode[pos] != key) pos++;
|
||||||
|
pos++;
|
||||||
|
}
|
||||||
|
|
||||||
|
void BeatMapLanInterpreter::jumpSpaces()
|
||||||
|
{
|
||||||
|
while (bmlCode[pos] == ' ') pos++;
|
||||||
|
}
|
||||||
|
|
||||||
|
vector<string> BeatMapLanInterpreter::popArgs()
|
||||||
|
{
|
||||||
|
vector<string> argsList;
|
||||||
|
|
||||||
|
while (bmlCode[pos] != key_fun_args_closing_bracket)
|
||||||
|
{
|
||||||
|
jumpSpaces();
|
||||||
|
argsList.push_back(pop_next(key_args_seperator));
|
||||||
|
}
|
||||||
|
pos++;
|
||||||
|
|
||||||
|
return argsList;
|
||||||
|
}
|
||||||
|
|
||||||
|
void BeatMapLanInterpreter::addOrAssignVar(string name, string value)
|
||||||
|
{
|
||||||
|
for (BmlVariable &variable : variables)
|
||||||
|
{
|
||||||
|
if (name.compare(variable.name))
|
||||||
|
{
|
||||||
|
variable.value = value;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
variables.push_back({ name, value });
|
||||||
|
}
|
||||||
|
|
||||||
|
string BeatMapLanInterpreter::getVarVal(string name)
|
||||||
|
{
|
||||||
|
for (BmlVariable &var : variables)
|
||||||
|
{
|
||||||
|
if (var.name == name)
|
||||||
|
{
|
||||||
|
return var.value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return error_variable_not_found;
|
||||||
|
}
|
||||||
|
|
||||||
|
string BeatMapLanInterpreter::evalMathExpression()
|
||||||
|
{
|
||||||
|
jumpSpaces();
|
||||||
|
string varOne = pop_next(' ');
|
||||||
|
jumpSpaces();
|
||||||
|
string operation = pop_next(' ');
|
||||||
|
jumpSpaces();
|
||||||
|
string varTwo = pop_next(' ');
|
||||||
|
|
||||||
|
gotoNext(key_math_closing_bracket);
|
||||||
|
|
||||||
|
if (operation.compare("+"))
|
||||||
|
{
|
||||||
|
return to_string(atof(varOne.c_str()) + atof(varTwo.c_str()));
|
||||||
|
}
|
||||||
|
else if (operation.compare("-"))
|
||||||
|
{
|
||||||
|
return to_string(atof(varOne.c_str()) - atof(varTwo.c_str()));
|
||||||
|
}
|
||||||
|
else if (operation.compare("*"))
|
||||||
|
{
|
||||||
|
return to_string(atof(varOne.c_str()) * atof(varTwo.c_str()));
|
||||||
|
}
|
||||||
|
else if (operation.compare("/"))
|
||||||
|
{
|
||||||
|
return to_string(atof(varOne.c_str()) / atof(varTwo.c_str()));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return error_invalid_math_operator;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
string BeatMapLanInterpreter::executeFun(int m_pos, vector<string> args_names, vector<string> args)
|
||||||
|
{
|
||||||
|
int old_pos = pos;
|
||||||
|
pos = m_pos;
|
||||||
|
|
||||||
|
gotoNext(key_block_opening_bracket);
|
||||||
|
jumpSpaces();
|
||||||
|
|
||||||
|
while (bmlCode[pos] != key_block_closing_bracket)
|
||||||
|
{
|
||||||
|
if (bmlCode[pos] == key_comment)
|
||||||
|
{
|
||||||
|
pos++;
|
||||||
|
gotoNext(key_comment);
|
||||||
|
}
|
||||||
|
else if (bmlCode[pos] == key_pattern)
|
||||||
|
{
|
||||||
|
pos++;
|
||||||
|
|
||||||
|
string timestamp = pop_next(key_pattern_seperator);
|
||||||
|
string t_inverted = pop_next(key_pattern_seperator);
|
||||||
|
int runs = atof(pop_next(' ').c_str());
|
||||||
|
|
||||||
|
double old_offset = currentOffset;
|
||||||
|
currentOffset += atof(timestamp.c_str());
|
||||||
|
|
||||||
|
bool old_inverted = inverted;
|
||||||
|
inverted = t_inverted.compare("true"); //Converting from string to bool
|
||||||
|
|
||||||
|
for (int i = 0; i < runs; i++)
|
||||||
|
{
|
||||||
|
currentOffset += atof(executeFun(pos, vector<string>{ "p_timestamp", "p_inverted", "p_total_runs", "p_current_run_index" }, vector<string>{ timestamp, t_inverted, to_string(runs), to_string(i)}).c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
gotoNext(key_block_closing_bracket);
|
||||||
|
|
||||||
|
currentOffset = old_offset;
|
||||||
|
inverted = old_inverted;
|
||||||
|
}
|
||||||
|
else if (bmlCode[pos] == key_return_p1 && bmlCode[pos + 1] == key_return_p2)
|
||||||
|
{
|
||||||
|
pos += 2;
|
||||||
|
jumpSpaces();
|
||||||
|
string s_out = pop_next(' ');
|
||||||
|
pos = old_pos;
|
||||||
|
return s_out;
|
||||||
|
}
|
||||||
|
else if (bmlCode[pos] == key_variable)
|
||||||
|
{
|
||||||
|
pos++;
|
||||||
|
string var_name = pop_next(' ');
|
||||||
|
jumpSpaces();
|
||||||
|
if (bmlCode[pos] == key_assignment)
|
||||||
|
{
|
||||||
|
pos++;
|
||||||
|
jumpSpaces();
|
||||||
|
addOrAssignVar(var_name, pop_next(' '));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
string fun_call = pop_next(' ');
|
||||||
|
gotoNext(key_fun_args_opening_bracket);
|
||||||
|
callFunction(fun_call, popArgs());
|
||||||
|
}
|
||||||
|
|
||||||
|
jumpSpaces();
|
||||||
|
}
|
||||||
|
|
||||||
|
pos = old_pos;
|
||||||
|
|
||||||
|
return no_return;
|
||||||
|
}
|
||||||
|
|
||||||
|
string BeatMapLanInterpreter::callFunction(string name, vector<string> args)
|
||||||
|
{
|
||||||
|
if (name == fun_place_cube)
|
||||||
|
{
|
||||||
|
externalFunctions.p_cube(atof(args[0].c_str()), atoi(args[1].c_str()), atoi(args[2].c_str()));
|
||||||
|
return no_return;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//Now we have to check for custom functions
|
||||||
|
|
||||||
|
for (BmlFunction &fun : functions)
|
||||||
|
{
|
||||||
|
if (fun.name.compare(name))
|
||||||
|
{
|
||||||
|
int old_pos = pos;
|
||||||
|
pos = fun.pos;
|
||||||
|
|
||||||
|
vector<string> arg_names = popArgs();
|
||||||
|
|
||||||
|
pos = old_pos;
|
||||||
|
|
||||||
|
return executeFun(fun.pos, arg_names, args);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return error_function_not_found;
|
||||||
|
}
|
||||||
85
Source/MediocreMapper/BeatLanguage.h
Normal file
85
Source/MediocreMapper/BeatLanguage.h
Normal file
@@ -0,0 +1,85 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
class BeatMapLanInterpreter
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
//typedefs
|
||||||
|
typedef void placeCube(double timestamp, int type, int value);
|
||||||
|
|
||||||
|
struct extFuns {
|
||||||
|
placeCube * p_cube;
|
||||||
|
};
|
||||||
|
|
||||||
|
extFuns externalFunctions;
|
||||||
|
|
||||||
|
//Public Constants
|
||||||
|
const string error_variable_not_found = "VARIABLE_NOT_FOUND";
|
||||||
|
const string error_invalid_math_operator = "INVALID_OPERATOR";
|
||||||
|
const string error_function_not_found = "FUNCTION_NOT_FOUND";
|
||||||
|
const string no_return = "NO_RETURN";
|
||||||
|
|
||||||
|
struct BmlVariable {
|
||||||
|
string name;
|
||||||
|
string value;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct BmlFunction {
|
||||||
|
string name;
|
||||||
|
int pos;
|
||||||
|
};
|
||||||
|
|
||||||
|
//Functions
|
||||||
|
BeatMapLanInterpreter(extFuns functions);
|
||||||
|
~BeatMapLanInterpreter();
|
||||||
|
|
||||||
|
void interpret(string code);
|
||||||
|
private:
|
||||||
|
//Constants
|
||||||
|
const char key_fun = '#';
|
||||||
|
const char key_comment = '<EFBFBD>';
|
||||||
|
const char key_pattern = '!';
|
||||||
|
const char key_pattern_seperator = ':';
|
||||||
|
const char key_block_opening_bracket = '{';
|
||||||
|
const char key_block_closing_bracket = '}';
|
||||||
|
const char key_math_opening_bracket = '[';
|
||||||
|
const char key_math_closing_bracket = ']';
|
||||||
|
const char key_section_marker = '"';
|
||||||
|
const char key_variable = '_';
|
||||||
|
const char key_assignment = '=';
|
||||||
|
const char key_request_return = '?';
|
||||||
|
const char key_return_p1 = '<';
|
||||||
|
const char key_return_p2 = '-';
|
||||||
|
const char key_fun_args_opening_bracket = '(';
|
||||||
|
const char key_fun_args_closing_bracket = ')';
|
||||||
|
const char key_args_seperator = ',';
|
||||||
|
|
||||||
|
const string fun_type_function = "fun";
|
||||||
|
const string fun_type_main = "main";
|
||||||
|
|
||||||
|
const string fun_place_cube = "Cube";
|
||||||
|
|
||||||
|
//Global Vriables
|
||||||
|
double currentOffset = 0.0;
|
||||||
|
bool inverted = false;
|
||||||
|
|
||||||
|
string bmlCode = "";
|
||||||
|
int pos = 0;
|
||||||
|
|
||||||
|
vector<BmlVariable> variables;
|
||||||
|
vector<BmlFunction> functions;
|
||||||
|
|
||||||
|
//Fuctions
|
||||||
|
string pop_next(char escape_char);
|
||||||
|
void gotoNext(char key);
|
||||||
|
void jumpSpaces();
|
||||||
|
vector<string> popArgs();
|
||||||
|
void addOrAssignVar(string name, string value);
|
||||||
|
string getVarVal(string name);
|
||||||
|
string evalMathExpression();
|
||||||
|
string executeFun(int m_pos, vector<string> args_names, vector<string> args);
|
||||||
|
string callFunction(string name, vector<string> args);
|
||||||
|
};
|
||||||
Reference in New Issue
Block a user