Implemented most of the code for choices

This commit is contained in:
Ryan Ward 2020-08-29 00:41:56 -04:00
parent 8464b62907
commit e6e5311a04
9 changed files with 577 additions and 288 deletions

View File

@ -25,6 +25,7 @@ namespace dms {
void prev();
std::vector<tokens::token> next(tokens::tokentype to,tokens::tokentype tc);
tokens::token peek();
tokens::token last();
std::vector<tokens::token> next(tokens::tokentype tk);
bool match(tokens::tokentype t1 = tokens::none, tokens::tokentype t2 = tokens::none, tokens::tokentype t3 = tokens::none, tokens::tokentype t4 = tokens::none, tokens::tokentype t5 = tokens::none, tokens::tokentype t6 = tokens::none, tokens::tokentype t7 = tokens::none, tokens::tokentype t8 = tokens::none, tokens::tokentype t9 = tokens::none, tokens::tokentype t10 = tokens::none, tokens::tokentype t11 = tokens::none, tokens::tokentype t12 = tokens::none);
bool match(tokens::tokentype* t1 = nullptr, tokens::tokentype* t2 = nullptr, tokens::tokentype* t3 = nullptr, tokens::tokentype* t4 = nullptr, tokens::tokentype* t5 = nullptr, tokens::tokentype* t6 = nullptr, tokens::tokentype* t7 = nullptr, tokens::tokentype* t8 = nullptr, tokens::tokentype* t9 = nullptr, tokens::tokentype* t10 = nullptr, tokens::tokentype* t11 = nullptr, tokens::tokentype* t12 = nullptr);
@ -61,16 +62,16 @@ namespace dms {
bool match_process_debug(tokenstream* stream);
bool match_process_disp(tokenstream* stream);
bool match_process_choice(tokenstream* stream);
bool match_process_function(tokenstream* stream, value* v=nullptr);
bool match_process_function(tokenstream* stream, value* v=nullptr, bool nested = true);
bool match_process_goto(tokenstream* stream);
bool match_process_jump(tokenstream* stream);
bool match_process_exit(tokenstream* stream);
bool match_process_label(tokenstream* stream);
bool match_process_expression(tokenstream* stream);
bool match_process_expression(tokenstream* stream, value* v);
bool match_process_IFFF(tokenstream* stream);
// Utils
bool createBlock(std::string bk_name, blocktype bk_type);
bool isExpression(tokenstream* stream);
bool isBlock();
bool isBlock(blocktype bk_type);
void tolower(std::string &str);

View File

@ -49,15 +49,115 @@ namespace dms {
return false;
}
bool LineParser::match_process_choice(tokenstream* stream) {
token temp = stream->peek();
if (temp.raw == codes::CHOI && stream->match(tokens::control,tokens::string)) {
// Let's parse choice blocks.
print(stream->peek());
stream->next();
std::string prompt = stream->next().name;
print("Prompt: ", prompt);
bool good = true;
std::string option;
cmd* c = new cmd;
// Create a unique label name by using the line number
std::string choicelabel = concat("$CHOI_END_", stream->peek().line_num);
c->opcode = codes::CHOI;
c->args.push(buildValue(prompt));
current_chunk->addCmd(c); // We will keep a reference to this and add to it as we go through the list
bool start = false;
/*
What's going on here might be tough to understand just by looking at the code
The bytecode generated by this code might look something like this:
off op opcodes
0 CHOI "Pick one!" "Choice 1" "Choice 2" "Choice 3" "Choice 4"
1 FUNC print "You picked 1!"
2 GOTO $CHOI_END_1
3 FUNC print "You picked 2!"
4 GOTO $CHOI_END_1
5 JUMP park
6 NOOP
7 GOTO mylabel
8 LABL $CHOI_END_1
The CHOI code tells the vm that we need to process user input. The input we get in a number 0-3
I know we have 4 choices
If the user provides us with a 0 then we need to move to off 1
If the user provides us with a 1 then we need to move to off 3
If the user provides us with a 2 then we need to move to off 5
If the user provides us with a 3 then we need to move to off 7
I'm sure you see the pattern here. 1 (+2) 3 (+2) 5... We only need to jump once then let the vm continue like normal.
The math for this is: [current_pos] + (n*2+1)
n*2+1 (n = 0) = 1
n*2+1 (n = 1) = 3
n*2+1 (n = 2) = 5
n*2+1 (n = 3) = 7
Which is why you see NOOP for the JUMP code. If GOTO wasn't the last choice possible to make there would be a NOOP after that as well.
The NOOP ensures the pattern stays.
If we are provided with a number greater than 3 then we can push an execption.
*/
while (!stream->match(tokens::cbracketc)) {
// We need to match the possible options for a choice block
/*
"option" function()
"option" goto ""
"option" goto var
"option" jump ""
"option" jump var
"option" exit [0]
Exit takes an optional int
*/
if (stream->match(tokens::cbracketo) && !start) {
start = true;
stream->next();
}
else if (stream->match(tokens::cbracketo) && start) {
state->push_error(errors::error{ errors::choice_unknown,concat("Unexpected symbol ",stream->next()),true,stream->peek().line_num });
}
else if (stream->match(tokens::string)) {
std::string name = stream->next().name;
print("Option: ", name);
c->args.push(buildValue(name)); // We append the choice to the first part of the CHOI cmd
// We consumed the option now lets do some matching, note that all of these are one liners in the bytecode!
if (match_process_function(stream,nullptr,false)) { // No returns and also no nesting of functions!
}
else if (match_process_goto(stream)) {
current_chunk->addCmd(new cmd{codes::NOOP }); // Add noop to post-goto command
}
else if (match_process_jump(stream)) {
current_chunk->addCmd(new cmd{ codes::NOOP }); // Add noop to post-jump command
}
else if (match_process_exit(stream)) {
current_chunk->addCmd(new cmd{ codes::NOOP }); // Add noop to post-exit command
}
}
// Last Match
else if (stream->match(tokens::newline)) {
stream->next(); // Consume
}
else if (!stream->match(tokens::cbracketc)) {
state->push_error(errors::error{ errors::choice_unknown,concat("Unexpected symbol ",stream->next()),true,stream->peek().line_num });
}
}
return true;
}
return false;
}
void cleanup(value* v) {
v->nuke(); // Make sure we clean up the data
delete[] v; // We didn't need it, lets clean it up!
}
/// <summary>
/// Recursively parse through function related tokens
/// </summary>
/// <param name="stream"></param>
/// <param name="v"></param>
/// <returns></returns>
bool LineParser::match_process_function(tokenstream* stream, value* v) {
bool LineParser::match_process_function(tokenstream* stream, value* v, bool nested) {
/*
Functions should be able to handle function calls as arguments,
HOWEVER functions cannot be passed as values since they aren't values like they are in other languages!
@ -116,34 +216,73 @@ namespace dms {
// Next we add arguments this is where things get interesting
tokenstream tempstream;
// This is a balanced consuming method (()(()))
std::vector<token> t = stream->next(tokens::parao, tokens::parac);
tempstream.init(&t);
tokens::token tok;
std::vector<token> t = stream->next(tokens::parao, tokens::parac); // Consume and get tokens
tempstream.init(&t); // Turn tokens we consumed into a tokenstream
value* tempval;
token tok;
// This part we add values to the opcodes for the bytecode FUNC val a1 a2 a3 ... an
while (tempstream.peek().type != tokens::none) { // End of stream
if (tempstream.match(tokens::string)) {
// We have a string argument
tempval = buildVariable();
tok = tempstream.peek();
if (tempstream.match(tokens::seperator)) {
// We have a seperator for function arguments
tempstream.next(); // Consume it
cleanup(tempval); // We don't need it
}
else if (tempstream.match(tokens::string)) {
cleanup(tempval);
tempval = buildValue(tempstream.next().name); // Get the string
c->args.push(tempval); // add this argument to the function opcodes
}
else if (tempstream.match(tokens::number)) {
// This is an interesting one This could be just a number, or an expression with functions n stuff
cleanup(tempval);
std::string str = tempstream.next().name;
tempval = buildValue(std::stod(str)); // Get the number and convert it to a double then build a value
c->args.push(tempval); // add this argument to the function opcodes
}
else if (match_process_expression(&tempstream)) {
else if (tempstream.match(tokens::True)) {
cleanup(tempval);
tempval = buildValue(true);
c->args.push(tempval);
tempstream.next();
}
else if (tempstream.match(tokens::False)) {
cleanup(tempval);
tempval = buildValue(false);
c->args.push(tempval);
tempstream.next();
}
else if (match_process_expression(&tempstream, tempval)) {
// We have an expression and its been handled Whoo!!!
}
// Final match this could be a function it might also be an expression
else if (match_process_function(&tempstream, buildVariable(""))) {
else if (match_process_function(&tempstream, tempval)) {
if (!nested) {
print("No nested!");
state->push_error(errors::error{ errors::nested_function,"Nested functions are not allowed in this context!",true, tempstream.peek().line_num });
}
else if (tempstream.match(tokens::seperator)) {
// We have a seperator for function arguments
tempstream.next(); // Consume it
print("Nested ok!");
c->args.push(tempval);
}
else if (tempstream.match(tokens::name)) {
cleanup(tempval);
tempval = buildVariable(tempstream.next().name);
c->args.push(tempval);
}
/*std::cout << "---Tokens---" << std::endl;
for (size_t i = 0; i < t.size() - 1; i++) {
std::cout << t[i] << std::endl;
}*/
else if (tempstream.match(tokens::newline)) {
tempstream.next();
}
else if (tempstream.match(tokens::parac)) {
cleanup(tempval);
tempstream.next();
current_chunk->addCmd(c); // We push this onto the chunk after all dependants if any have been handled
wait();
return true;
}
else {
cleanup(tempval); // Cleanup
state->push_error(errors::error{ errors::badtoken,concat("Invalid symbol: ",tempstream.peek()),true, tempstream.peek().line_num});
}
}
}
return false;
}
@ -159,25 +298,63 @@ namespace dms {
bool LineParser::match_process_label(tokenstream* stream) {
return false;
}
bool LineParser::match_process_expression(tokenstream* stream) {
bool LineParser::match_process_IFFF(tokenstream* stream) {
return false;
}
bool LineParser::match_process_expression(tokenstream* stream, value* v) {
return false; // Method isn't done yet, we will get an error without this!
// I will have to consume for this to work so we need to keep track of what was incase we return false!
size_t start_pos = stream->pos;
// It has to start with one of these 3 to even be considered an expression
if (stream->match(tokens::number) || stream->match(tokens::name) || stream->match(tokens::parao)) {
// What do we know, math expressions can only be on a single line. We know where to stop looking if we have to
token t = stream->peek();
cmd* c = new cmd;
/*
* We have a few built-in methods we will have to handle
* ADD val v1 v2
* SUB val v1 v2
* MUL val v1 v2
* DIV val v1 v2
* POW val v1 v2
* MOD val v1 v2
*/
/* lua code which was actually really compact and works!
if not expr:match("[/%^%+%-%*%%]") then --[[print("No math to do!")]] return expr end
-- handle pharanses
expr=expr:gsub("([%W])(%-%d)",function(b,a)
return b.."(0-"..a:match("%d+")..")"
end)
-- Work on functions
expr = expr:gsub("([_%w]+)(%b())",function(func,args)
local v = gen("$")
local fnwr = {self.current_line[1],self.current_line[2],FWNR,self.current_line[4],v.." = "..func..args}
self:parseFNWR(fnwr)
return v
end)
expr = expr:gsub("(%b())",function(a)
return self:parseExpr(a:sub(2,-2))
end)
return self:chop(expr)
*/
token left; // lefthand
token op; // opperator
token right; // righthand
while (stream->peek().type != tokens::none) {
if (t.type == tokens::parao) {
tokenstream temp;
temp.init(&(stream->next(tokens::parao, tokens::parac))); // Balanced match!
return match_process_expression(&temp); // Return true is everything else checks out!
return match_process_expression(&temp,buildVariable("Work On This")); // Return true is everything else checks out!
}
// We have a number
else if (t.type == tokens::number) {
}
}
}
else {
return stream->restore(start_pos); // Always return false and restores the position in stream!
}
}
}
}

View File

@ -53,10 +53,10 @@ namespace dms {
stream.next('\n'); // Seek until you find a newline
}
else if (data == '\n') {
doCheck(&stream, &t_vec, line, isNum, hasDec, &buffer);
t_vec.push_back(token{ tokens::newline,codes::NOOP,"",line });
doCheck(&stream, &t_vec, line-2, isNum, hasDec, &buffer);
t_vec.push_back(token{ tokens::newline,codes::NOOP,"",line - 2 });
if (isNum) {
t_vec.push_back(token{ tokens::number,codes::NOOP,stream.processBuffer(buffer),line });
t_vec.push_back(token{ tokens::number,codes::NOOP,stream.processBuffer(buffer),line - 2 });
buffer.clear();
isNum = false;
}
@ -71,7 +71,7 @@ namespace dms {
stream.next();
}
else if (data == ':' && stream.peek() == ':' && labelStart) {
t_vec.push_back(token{ tokens::label,codes::NOOP,stream.processBuffer(buffer),line });
t_vec.push_back(token{ tokens::label,codes::NOOP,stream.processBuffer(buffer),line - 2 });
buffer.clear();
stream.next();
labelStart = false;
@ -82,9 +82,12 @@ namespace dms {
}
else if (data == '"' && isStr) {
isStr = false;
t_vec.push_back(token{ tokens::string,codes::NOOP,stream.processBuffer(buffer),line });
t_vec.push_back(token{ tokens::string,codes::NOOP,stream.processBuffer(buffer),line - 2 });
buffer.clear();
}
else if (isStr) {
buffer.push_back(data);
}
else if (isdigit(data)) {
isNum = true;
buffer.push_back(data);
@ -97,153 +100,157 @@ namespace dms {
buffer.push_back(data);
}
else if (data == '.' && isNum && hasDec) {
t_vec.push_back(token{ tokens::number,codes::ERRO,"Malformed number!",line });
t_vec.push_back(token{ tokens::number,codes::ERRO,"Malformed number!",line - 2 });
}
else if (data == '[') {
doCheck(&stream, &t_vec, line, isNum, hasDec, &buffer);
t_vec.push_back(token{ tokens::bracketo,codes::NOOP,"",line });
doCheck(&stream, &t_vec, line - 2, isNum, hasDec, &buffer);
t_vec.push_back(token{ tokens::bracketo,codes::NOOP,"",line - 2 });
}
else if (data == ']') {
doCheck(&stream, &t_vec, line, isNum, hasDec, &buffer);
t_vec.push_back(token{ tokens::bracketc,codes::NOOP,"",line });
doCheck(&stream, &t_vec, line - 2, isNum, hasDec, &buffer);
t_vec.push_back(token{ tokens::bracketc,codes::NOOP,"",line - 2 });
}
else if (data == '(') {
doCheck(&stream, &t_vec, line, isNum, hasDec, &buffer);
t_vec.push_back(token{ tokens::parao,codes::NOOP,"",line });
doCheck(&stream, &t_vec, line - 2, isNum, hasDec, &buffer);
t_vec.push_back(token{ tokens::parao,codes::NOOP,"",line - 2 });
}
else if (data == ')') {
doCheck(&stream, &t_vec, line, isNum, hasDec, &buffer);
t_vec.push_back(token{ tokens::parac,codes::NOOP,"",line });
doCheck(&stream, &t_vec, line - 2, isNum, hasDec, &buffer);
t_vec.push_back(token{ tokens::parac,codes::NOOP,"",line - 2 });
}
else if (data == ',') {
doCheck(&stream, &t_vec, line, isNum, hasDec, &buffer);
t_vec.push_back(token{ tokens::seperator,codes::NOOP,"",line });
doCheck(&stream, &t_vec, line - 2, isNum, hasDec, &buffer);
t_vec.push_back(token{ tokens::seperator,codes::NOOP,"",line - 2 });
}
else if (data == '.') {
//doCheck(&stream, &t_vec, line, isNum, hasDec, &buffer);
t_vec.push_back(token{ tokens::dot,codes::NOOP,"",line });
t_vec.push_back(token{ tokens::dot,codes::NOOP,"",line - 2 });
}
else if (data == '{') {
doCheck(&stream, &t_vec, line, isNum, hasDec, &buffer);
t_vec.push_back(token{ tokens::cbracketo,codes::NOOP,"",line });
doCheck(&stream, &t_vec, line - 2, isNum, hasDec, &buffer);
t_vec.push_back(token{ tokens::cbracketo,codes::NOOP,"",line - 2 });
}
else if (data == '}') {
doCheck(&stream, &t_vec, line, isNum, hasDec, &buffer);
t_vec.push_back(token{ tokens::cbracketc,codes::NOOP,"",line });
doCheck(&stream, &t_vec, line - 2, isNum, hasDec, &buffer);
t_vec.push_back(token{ tokens::cbracketc,codes::NOOP,"",line - 2 });
}
else if (data == '+') {
doCheck(&stream, &t_vec, line, isNum, hasDec, &buffer);
t_vec.push_back(token{ tokens::plus,codes::NOOP,"",line });
doCheck(&stream, &t_vec, line - 2, isNum, hasDec, &buffer);
t_vec.push_back(token{ tokens::plus,codes::NOOP,"",line - 2 });
}
else if (data == '-') {
doCheck(&stream, &t_vec, line, isNum, hasDec, &buffer);
t_vec.push_back(token{ tokens::minus,codes::NOOP,"",line });
doCheck(&stream, &t_vec, line - 2, isNum, hasDec, &buffer);
t_vec.push_back(token{ tokens::minus,codes::NOOP,"",line - 2 });
}
else if (data == '*') {
doCheck(&stream, &t_vec, line, isNum, hasDec, &buffer);
t_vec.push_back(token{ tokens::multiply,codes::NOOP,"",line });
doCheck(&stream, &t_vec, line - 2, isNum, hasDec, &buffer);
t_vec.push_back(token{ tokens::multiply,codes::NOOP,"",line - 2 });
}
else if (data == '/') {
doCheck(&stream, &t_vec, line, isNum, hasDec, &buffer);
t_vec.push_back(token{ tokens::divide,codes::NOOP,"",line });
doCheck(&stream, &t_vec, line - 2, isNum, hasDec, &buffer);
t_vec.push_back(token{ tokens::divide,codes::NOOP,"",line - 2 });
}
else if (data == '^') {
doCheck(&stream, &t_vec, line, isNum, hasDec, &buffer);
t_vec.push_back(token{ tokens::pow,codes::NOOP,"",line });
doCheck(&stream, &t_vec, line - 2, isNum, hasDec, &buffer);
t_vec.push_back(token{ tokens::pow,codes::NOOP,"",line - 2 });
}
else if (data == '%') {
doCheck(&stream, &t_vec, line, isNum, hasDec, &buffer);
t_vec.push_back(token{ tokens::mod,codes::NOOP,"",line });
doCheck(&stream, &t_vec, line - 2, isNum, hasDec, &buffer);
t_vec.push_back(token{ tokens::mod,codes::NOOP,"",line - 2 });
}
else if (data == '=') {
doCheck(&stream, &t_vec, line, isNum, hasDec, &buffer);
t_vec.push_back(token{ tokens::equal,codes::NOOP,"",line });
doCheck(&stream, &t_vec, line - 2, isNum, hasDec, &buffer);
t_vec.push_back(token{ tokens::equal,codes::NOOP,"",line - 2 });
}
else if (data == ':') {
doCheck(&stream, &t_vec, line, isNum, hasDec, &buffer);
t_vec.push_back(token{ tokens::colon,codes::NOOP,"",line });
doCheck(&stream, &t_vec, line - 2, isNum, hasDec, &buffer);
t_vec.push_back(token{ tokens::colon,codes::NOOP,"",line - 2 });
}
else if (data == ';') {
doCheck(&stream, &t_vec, line, isNum, hasDec, &buffer);
t_vec.push_back(token{ tokens::newline,codes::NOOP,"",line });
doCheck(&stream, &t_vec, line - 2, isNum, hasDec, &buffer);
t_vec.push_back(token{ tokens::newline,codes::NOOP,"",line - 2 });
}
else if (data == '!') {
doCheck(&stream, &t_vec, line, isNum, hasDec, &buffer);
t_vec.push_back(token{ tokens::Not,codes::NOOP,"",line });
doCheck(&stream, &t_vec, line - 2, isNum, hasDec, &buffer);
t_vec.push_back(token{ tokens::Not,codes::NOOP,"",line - 2 });
}
else if (data == '\t') {
doCheck(&stream, &t_vec, line, isNum, hasDec, &buffer);
t_vec.push_back(token{ tokens::tab,codes::NOOP,"",line });
doCheck(&stream, &t_vec, line - 2, isNum, hasDec, &buffer);
t_vec.push_back(token{ tokens::tab,codes::NOOP,"",line - 2 });
}
if (data == ' ' && !isStr) { // tokens end with a space
std::string str = stream.processBuffer(buffer);
tolower(str);
if (str == "enable") {
t_vec.push_back(token{ tokens::flag,codes::ENAB,"",line });
t_vec.push_back(token{ tokens::flag,codes::ENAB,"",line - 2 });
}
else if (str == "entry") {
t_vec.push_back(token{ tokens::flag,codes::ENTR,"",line });
t_vec.push_back(token{ tokens::flag,codes::ENTR,"",line - 2 });
}
else if (str == "loadfile") {
t_vec.push_back(token{ tokens::flag,codes::LOAD,"",line });
t_vec.push_back(token{ tokens::flag,codes::LOAD,"",line - 2 });
}
else if (str == "version") {
t_vec.push_back(token{ tokens::flag,codes::VERN,"",line });
t_vec.push_back(token{ tokens::flag,codes::VERN,"",line - 2 });
}
else if (str == "using") {
t_vec.push_back(token{ tokens::flag,codes::USIN,"",line });
t_vec.push_back(token{ tokens::flag,codes::USIN,"",line - 2 });
}
else if (str == "disable") {
t_vec.push_back(token{ tokens::flag,codes::DISA,"",line });
t_vec.push_back(token{ tokens::flag,codes::DISA,"",line - 2 });
}
else if (str == "if") {
t_vec.push_back(token{ tokens::control,codes::IFFF,"",line });
t_vec.push_back(token{ tokens::control,codes::IFFF,"",line - 2 });
}
else if (str == "elseif") {
t_vec.push_back(token{ tokens::control,codes::ELIF,"",line });
t_vec.push_back(token{ tokens::control,codes::ELIF,"",line - 2 });
}
else if (str == "while") {
t_vec.push_back(token{ tokens::control,codes::WHLE,"",line });
t_vec.push_back(token{ tokens::control,codes::WHLE,"",line - 2 });
}
else if (str == "true") {
t_vec.push_back(token{ tokens::True,codes::NOOP,"",line });
t_vec.push_back(token{ tokens::True,codes::NOOP,"",line - 2 });
}
else if (str == "false") {
t_vec.push_back(token{ tokens::False,codes::NOOP,"",line });
t_vec.push_back(token{ tokens::False,codes::NOOP,"",line - 2 });
}
else if (str == "else") {
t_vec.push_back(token{ tokens::control,codes::ELSE,"",line });
t_vec.push_back(token{ tokens::control,codes::ELSE,"",line - 2 });
}
else if (str == "and") {
t_vec.push_back(token{ tokens::And,codes::NOOP,"",line });
t_vec.push_back(token{ tokens::And,codes::NOOP,"",line - 2 });
}
else if (str == "or") {
t_vec.push_back(token{ tokens::Or,codes::NOOP,"",line });
t_vec.push_back(token{ tokens::Or,codes::NOOP,"",line - 2 });
}
else if (str == "for") {
t_vec.push_back(token{ tokens::For,codes::NOOP,"",line });
t_vec.push_back(token{ tokens::For,codes::NOOP,"",line - 2 });
}
else if (str == "choice") {
t_vec.push_back(token{ tokens::control,codes::CHOI,"",line });
t_vec.push_back(token{ tokens::control,codes::CHOI,"",line - 2 });
}
else if (str == "return") {
t_vec.push_back(token{ tokens::ret,codes::RETN,"",line });
t_vec.push_back(token{ tokens::ret,codes::RETN,"",line - 2 });
}
else if (str == "nil") {
t_vec.push_back(token{ tokens::nil,codes::NOOP,"",line });
t_vec.push_back(token{ tokens::nil,codes::NOOP,"",line - 2 });
}
else if (str == "goto") {
t_vec.push_back(token{ tokens::gotoo,codes::NOOP,"",line });
t_vec.push_back(token{ tokens::gotoo,codes::NOOP,"",line - 2 });
}
else if (str == "jump") {
t_vec.push_back(token{ tokens::jump,codes::NOOP,"",line });
t_vec.push_back(token{ tokens::jump,codes::NOOP,"",line - 2 });
}
else if (str == "exit") {
t_vec.push_back(token{ tokens::exit,codes::NOOP,"",line });
t_vec.push_back(token{ tokens::exit,codes::NOOP,"",line - 2 });
}
else if (utils::isNum(str) && str.size()!=0) {
t_vec.push_back(token{ tokens::number,codes::NOOP,stream.processBuffer(buffer),line - 2 });
isNum = false;
}
else if (utils::isalphanum(str) && str.size() > 0) {
t_vec.push_back(token{ tokens::name,codes::NOOP,stream.processBuffer(buffer),line });
t_vec.push_back(token{ tokens::name,codes::NOOP,stream.processBuffer(buffer),line - 2 });
}
else {
// Unknown command!
@ -255,7 +262,7 @@ namespace dms {
}
data = stream.next();
}
t_vec.push_back(token{ tokens::eof,codes::NOOP,"",line + 1 });
t_vec.push_back(token{ tokens::eof,codes::NOOP,"",line - 1 });
std::ofstream outputFile("dump.txt");
outputFile << "Token Dump:" << std::endl;
for (size_t i = 0; i < t_vec.size(); i++) {
@ -376,100 +383,11 @@ namespace dms {
}
// Control Handle all controls here
if (stream.match(tokens::control)) {
token control = stream.next();
if (control.raw == codes::CHOI && stream.peek().type == tokens::string) {
// Let's parse choice blocks.
std::string prompt = stream.next().name;
print("Prompt: ", prompt);
bool good = true;
std::string option;
cmd* c = new cmd;
// Create a unique label name by using the line number
std::string choicelabel = concat("$CHOI_END_", stream.peek().line_num);
wait();
c->opcode = codes::CHOI;
c->args.push(buildValue(prompt));
current_chunk->addCmd(c); // We will keep a reference to this and add to it as we go through the list
bool start = false;
/*
What's going on here might be tough to understand just by looking at the code
The bytecode generated by this code might look something like this:
off op opcodes
0 CHOI "Pick one!" "Choice 1" "Choice 2" "Choice 3" "Choice 4"
1 FUNC print "You picked 1!"
2 GOTO $CHOI_END_1
3 FUNC print "You picked 2!"
4 GOTO $CHOI_END_1
5 JUMP park
6 NOOP
7 GOTO mylabel
8 LABL $CHOI_END_1
The CHOI code tells the vm that we need to process user input. The input we get in a number 0-3
I know we have 4 choices
If the user provides us with a 0 then we need to move to off 1
If the user provides us with a 1 then we need to move to off 3
If the user provides us with a 2 then we need to move to off 5
If the user provides us with a 3 then we need to move to off 7
I'm sure you see the pattern here. 1 (+2) 3 (+2) 5... We only need to jump once then let the vm continue like normal.
The math for this is: [current_pos] + (n*2+1)
n*2+1 (n = 0) = 1
n*2+1 (n = 1) = 3
n*2+1 (n = 2) = 5
n*2+1 (n = 3) = 7
Which is why you see NOOP for the JUMP code. If GOTO wasn't the last choice possible to make there would be a NOOP after that as well.
The NOOP ensures the pattern stays.
If we are provided with a number greater than 3 then we can push an execption.
*/
while (!stream.match(tokens::cbracketc)) {
// We need to match the possible options for a choice block
/*
"option" function()
"option" goto ""
"option" goto var
"option" jump ""
"option" jump var
"option" exit [0]
Exit takes an optional int
*/
if (stream.match(tokens::cbracketo) && !start) {
start = true;
stream.next();
//token control = stream.next();
if (match_process_choice(&stream)) {
// Handle choice stuff
}
else if (stream.match(tokens::cbracketo) && start) {
state->push_error(errors::error{ errors::choice_unknown,concat("Unexpected symbol ",stream.next()),true,stream.peek().line_num });
}
else if (stream.match(tokens::string)) {
std::string name = stream.next().name;
print("Option: ", name);
c->args.push(buildValue(name)); // We append the choice to the first part of the CHOI cmd
// We consumed the option now lets do some matching, note that all of these are one liners in the bytecode!
if (match_process_function(&stream)) {
}
else if (match_process_goto(&stream)) {
}
else if (match_process_jump(&stream)) {
}
else if (match_process_exit(&stream)) {
}
}
// Last Match
else if (stream.match(tokens::newline)) {
stream.next(); // Consume
}
else if (!stream.match(tokens::cbracketc)) {
state->push_error(errors::error{ errors::choice_unknown,concat("Unexpected symbol ",stream.next()),true,stream.peek().line_num });
}
}
}
else if (control.raw == codes::IFFF) {
else if (match_process_IFFF(&stream)) {
// This will probably be the toughest one of them all
}
}

View File

@ -6,6 +6,9 @@ namespace dms {
void tokenstream::init(std::vector<token>* ptr) {
this->tokens = *ptr;
}
token tokenstream::last() {
return this->tokens[pos-1];
}
token tokenstream::next() {
if (pos > this->tokens.size())
return token{ tokentype::none,codes::NOOP,"EOS",0 };

View File

@ -1,128 +1,309 @@
Token Dump:
Line <18446744073709551615>NOOP newline
Line <0>NOOP newline
Line <1>ENTR flag
Line <1>NOOP name main
Line <1>NOOP newline
Line <2>ENAB flag
Line <2>NOOP name warnings
Line <2>NOOP newline
Line <3>NOOP bracketo
Line <3>NOOP name default
Line <3>NOOP colon
Line <3>NOOP name char
Line <3>NOOP bracketc
Line <3>DISA flag
Line <3>NOOP name omniscient
Line <3>NOOP newline
Line <4>NOOP newline
Line <5>NOOP name money
Line <5>NOOP equal
Line <5>NOOP number 0
Line <5>NOOP newline
Line <6>VERN flag
Line <6>NOOP number 1.2
Line <6>NOOP newline
Line <7>NOOP bracketo
Line <7>NOOP name Ryan
Line <7>NOOP colon
Line <7>NOOP name char
Line <7>NOOP bracketc
Line <7>USIN flag
Line <7>NOOP name extendedDefine
Line <7>NOOP newline
Line <8>NOOP name age
Line <8>NOOP equal
Line <8>NOOP number 21
Line <8>NOOP newline
Line <9>NOOP name money
Line <9>NOOP equal
Line <9>NOOP number 1000
Line <9>NOOP bracketo
Line <9>NOOP name main
Line <9>NOOP bracketc
Line <9>NOOP cbracketo
Line <9>NOOP newline
Line <10>NOOP name Ryan
Line <10>NOOP colon
Line <10>NOOP string This works!
Line <10>NOOP newline
Line <11>NOOP name calm
Line <11>NOOP colon
Line <11>NOOP string ./path/to/file
Line <11>NOOP name DEBUG
Line <11>NOOP string What's up
Line <11>NOOP newline
Line <12>NOOP name excited
Line <12>NOOP name Ryan
Line <12>NOOP colon
Line <12>NOOP string ./path/to/file
Line <12>NOOP cbracketo
Line <12>NOOP newline
Line <13>NOOP name speed
Line <13>NOOP number 100
Line <13>NOOP mod
Line <13>NOOP newline
Line <14>NOOP bracketo
Line <14>NOOP name step
Line <14>NOOP colon
Line <14>NOOP name function
Line <14>NOOP parao
Line <14>NOOP name a
Line <14>NOOP seperator
Line <14>NOOP name b
Line <14>NOOP seperator
Line <14>NOOP name c
Line <14>NOOP parac
Line <14>NOOP bracketc
Line <13>NOOP name calm
Line <13>NOOP string Hello Bob,
Line <13>NOOP newline
Line <14>NOOP name wait
Line <14>NOOP number 0.455
Line <14>NOOP newline
Line <15>NOOP string Testing...
Line <15>NOOP name excited
Line <15>NOOP string how are you doing?
Line <15>NOOP newline
Line <16>NOOP name d
Line <16>NOOP equal
Line <16>NOOP parao
Line <16>NOOP name 100
Line <16>NOOP number
Line <16>NOOP plus
Line <16>NOOP name b
Line <16>NOOP parac
Line <16>NOOP divide
Line <16>NOOP name c
Line <16>NOOP newline
Line <17>NOOP name e
Line <17>NOOP equal
Line <17>NOOP string somestring
Line <17>NOOP cbracketc
Line <17>NOOP newline
Line <18>NOOP name e
Line <18>NOOP equal
Line <18>NOOP nil nil
Line <18>NOOP newline
Line <19>NOOP name g
Line <19>NOOP name tester
Line <19>NOOP equal
Line <19>NOOP false false
Line <19>NOOP string Hello
Line <19>NOOP newline
Line <20>RETN ret
Line <20>NOOP name d
Line <20>NOOP name food
Line <20>NOOP equal
Line <20>NOOP number 3
Line <20>NOOP newline
Line <21>NOOP name a
Line <21>NOOP equal
Line <21>NOOP name list
Line <21>NOOP bracketo
Line <21>NOOP number 1
Line <21>NOOP bracketc
Line <21>NOOP newline
Line <22>NOOP bracketo
Line <22>NOOP name inventory
Line <22>NOOP colon
Line <22>NOOP name env
Line <22>NOOP bracketc
Line <22>NOOP newline
Line <23>NOOP name slot1
Line <23>NOOP number
Line <23>NOOP equal
Line <23>NOOP string
Line <23>IFFF control
Line <23>NOOP name statment
Line <23>NOOP cbracketo
Line <23>NOOP newline
Line <24>NOOP name slot2
Line <24>NOOP number
Line <24>NOOP equal
Line <24>NOOP string
Line <24>NOOP string test
Line <24>NOOP newline
Line <25>NOOP name slot3
Line <25>NOOP number
Line <25>NOOP equal
Line <25>NOOP string
Line <25>NOOP cbracketc
Line <25>ELIF control
Line <25>NOOP name statement
Line <25>NOOP cbracketo
Line <25>NOOP newline
Line <26>NOOP name slot4
Line <26>NOOP number
Line <26>NOOP equal
Line <26>NOOP string
Line <26>NOOP string test
Line <26>NOOP newline
Line <27>NOOP name slot5
Line <27>NOOP number
Line <27>NOOP equal
Line <27>NOOP string
Line <27>NOOP cbracketc
Line <27>IFFF control
Line <27>NOOP name statement
Line <27>NOOP cbracketo
Line <27>NOOP newline
Line <28>NOOP name slot6
Line <28>NOOP number
Line <28>NOOP equal
Line <28>NOOP string
Line <28>NOOP string test
Line <28>NOOP newline
Line <29>NOOP name slot7
Line <29>NOOP number
Line <29>NOOP equal
Line <29>NOOP string
Line <29>NOOP string test
Line <29>NOOP newline
Line <30>NOOP name slot8
Line <30>NOOP number
Line <30>NOOP equal
Line <30>NOOP string
Line <30>IFFF control
Line <30>NOOP name statement
Line <30>NOOP cbracketo
Line <30>NOOP newline
Line <32>NOOP eof
Line <31>NOOP string test
Line <31>NOOP newline
Line <32>NOOP cbracketc
Line <32>ELSE control
Line <32>NOOP cbracketo
Line <32>NOOP newline
Line <33>NOOP string test
Line <33>NOOP newline
Line <34>NOOP cbracketc
Line <34>NOOP newline
Line <35>NOOP cbracketc
Line <35>ELIF control
Line <35>NOOP name statement
Line <35>NOOP cbracketo
Line <35>NOOP newline
Line <36>NOOP string test
Line <36>NOOP newline
Line <37>NOOP cbracketc
Line <37>ELSE control
Line <37>NOOP cbracketo
Line <37>NOOP newline
Line <38>NOOP string test
Line <38>NOOP newline
Line <39>NOOP cbracketc
Line <39>NOOP newline
Line <40>NOOP newline
Line <41>NOOP gotoo
Line <41>NOOP string somewhere
Line <41>NOOP newline
Line <42>NOOP jump
Line <42>NOOP string overhere
Line <42>NOOP newline
Line <43>NOOP newline
Line <44>NOOP name hungry
Line <44>NOOP equal
Line <44>NOOP parao
Line <44>NOOP minus
Line <44>NOOP number 2
Line <44>NOOP plus
Line <44>NOOP number 4
Line <44>NOOP minus
Line <44>NOOP parao
Line <44>NOOP parao
Line <44>NOOP number 5
Line <44>NOOP multiply
Line <44>NOOP number 5
Line <44>NOOP parac
Line <44>NOOP divide
Line <44>NOOP name sqrt
Line <44>NOOP parao
Line <44>NOOP number 144
Line <44>NOOP plus
Line <44>NOOP number 5
Line <44>NOOP parac
Line <44>NOOP parac
Line <44>NOOP parac
Line <44>NOOP pow
Line <44>NOOP number 2
Line <44>NOOP multiply
Line <44>NOOP number 2
Line <44>NOOP plus
Line <44>NOOP number 2
Line <44>NOOP newline
Line <45>NOOP name list
Line <45>NOOP bracketo
Line <45>NOOP number 1
Line <45>NOOP bracketc
Line <45>NOOP equal
Line <45>NOOP string Hello
Line <45>NOOP newline
Line <46>NOOP name var1
Line <46>NOOP number
Line <46>NOOP equal
Line <46>NOOP name func
Line <46>NOOP parao
Line <46>NOOP number 1
Line <46>NOOP seperator
Line <46>NOOP string string
Line <46>NOOP seperator
Line <46>NOOP number 2
Line <46>NOOP plus
Line <46>NOOP number 5
Line <46>NOOP parac
Line <46>NOOP newline
Line <47>NOOP name a
Line <47>NOOP equal
Line <47>NOOP number 100
Line <47>NOOP plus
Line <47>NOOP name func
Line <47>NOOP parao
Line <47>NOOP number 1
Line <47>NOOP seperator
Line <47>NOOP string string
Line <47>NOOP seperator
Line <47>NOOP number 2
Line <47>NOOP plus
Line <47>NOOP number 5
Line <47>NOOP parac
Line <47>NOOP plus
Line <47>NOOP number 100
Line <47>NOOP newline
Line <48>NOOP name func
Line <48>NOOP parao
Line <48>NOOP number 1
Line <48>NOOP seperator
Line <48>NOOP string string
Line <48>NOOP seperator
Line <48>NOOP number 2
Line <48>NOOP plus
Line <48>NOOP number 5
Line <48>NOOP parac
Line <48>NOOP newline
Line <49>NOOP label label
Line <49>NOOP newline
Line <50>NOOP newline
Line <51>NOOP newline
Line <52>CHOI control
Line <52>NOOP string Pick one:
Line <52>NOOP cbracketo
Line <52>NOOP newline
Line <53>NOOP string first
Line <53>NOOP name func
Line <53>NOOP parao
Line <53>NOOP number 1
Line <53>NOOP seperator
Line <53>NOOP number 2
Line <53>NOOP seperator
Line <53>NOOP number 3
Line <53>NOOP parac
Line <53>NOOP newline
Line <54>NOOP string second
Line <54>NOOP name func
Line <54>NOOP parao
Line <54>NOOP true true
Line <54>NOOP seperator
Line <54>NOOP false false
Line <54>NOOP seperator
Line <54>NOOP name func
Line <54>NOOP parao
Line <54>NOOP string heehee
Line <54>NOOP parac
Line <54>NOOP parac
Line <54>NOOP newline
Line <55>NOOP string third
Line <55>NOOP name func
Line <55>NOOP parao
Line <55>NOOP string hehe
Line <55>NOOP parac
Line <55>NOOP newline
Line <56>NOOP string forth
Line <56>NOOP name func
Line <56>NOOP parao
Line <56>NOOP string 1
Line <56>NOOP seperator
Line <56>NOOP number 2
Line <56>NOOP seperator
Line <56>NOOP false false
Line <56>NOOP parac
Line <56>NOOP newline
Line <57>NOOP string fifth
Line <57>NOOP gotoo
Line <57>NOOP string here
Line <57>NOOP newline
Line <58>NOOP string sixth
Line <58>NOOP gotoo
Line <58>NOOP name name
Line <58>NOOP newline
Line <59>NOOP string sevinth
Line <59>NOOP jump
Line <59>NOOP string there
Line <59>NOOP newline
Line <60>NOOP string eight
Line <60>NOOP jump
Line <60>NOOP name name
Line <60>NOOP newline
Line <61>NOOP string nine
Line <61>NOOP name exit
Line <61>NOOP newline
Line <62>NOOP cbracketc
Line <62>NOOP newline
Line <63>NOOP cbracketc
Line <63>NOOP newline
Line <64>NOOP newline
Line <65>NOOP newline
Line <66>NOOP newline
Line <67>NOOP bracketo
Line <67>NOOP name Bob
Line <67>NOOP colon
Line <67>NOOP name char
Line <67>NOOP bracketc
Line <67>NOOP newline
Line <68>NOOP name age
Line <68>NOOP equal
Line <68>NOOP number 24
Line <68>NOOP newline
Line <69>NOOP name money
Line <69>NOOP equal
Line <69>NOOP number 100
Line <69>NOOP newline
Line <70>NOOP newline
Line <71>NOOP bracketo
Line <71>NOOP name newblock
Line <71>NOOP colon
Line <71>NOOP name function
Line <71>NOOP parao
Line <71>NOOP parac
Line <71>NOOP bracketc
Line <71>NOOP newline
Line <72>NOOP string Test #2
Line <72>NOOP newline
Line <73>NOOP string Does it parse this part properly?
Line <73>NOOP newline
Line <75>NOOP eof

View File

@ -5,11 +5,12 @@ namespace dms::errors {
unknown,
string_out_of_bounds,
invalid_arguments,
invalie_type,
invalid_type,
array_out_of_bounds,
badtoken,
block_already_defined,
choice_unknown
choice_unknown,
nested_function
};
struct error {
errortype code=unknown;

View File

@ -2,7 +2,7 @@ entry main
enable warnings
disable omniscient
//enable debugging
loadfile "loadtest.dms"
//loadfile "loadtest.dms"
version 1.2
using extendedDefine
@ -51,7 +51,7 @@ using extendedDefine
CHOICE "Pick one:" {
"first" func(1,2,3)
"second" func(true,false)
"second" func(true,false,func("heehee"))
"third" func("hehe")
"forth" func("1",2,false)
"fifth" goto "here"
@ -63,6 +63,7 @@ using extendedDefine
}
[Bob:char]
age = 24
money = 100

View File

@ -33,6 +33,12 @@ namespace dms {
value* buildValue() {
return new value;
}
size_t count = 0;
value* buildVariable() {
count++;
std::string val = utils::concat("$",count);
return buildVariable(val);
}
value* buildVariable(std::string str) {
value* val = new value{};
val->set(buildString(str));

View File

@ -85,6 +85,7 @@ namespace dms {
};
value* buildValue();
value* buildVariable(std::string str);
value* buildVariable();
value* buildValue(std::string str);
value* buildValue(double dbl);
value* buildValue(int i);