diff --git a/DMS/LineParser.h b/DMS/LineParser.h index c8e9788..a443cad 100644 --- a/DMS/LineParser.h +++ b/DMS/LineParser.h @@ -25,6 +25,7 @@ namespace dms { void prev(); std::vector next(tokens::tokentype to,tokens::tokentype tc); tokens::token peek(); + tokens::token last(); std::vector 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); diff --git a/DMS/LineParserMatchProcess.cpp b/DMS/LineParserMatchProcess.cpp index aa16574..330d965 100644 --- a/DMS/LineParserMatchProcess.cpp +++ b/DMS/LineParserMatchProcess.cpp @@ -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! + } /// /// Recursively parse through function related tokens /// /// /// /// - 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 t = stream->next(tokens::parao, tokens::parac); - tempstream.init(&t); - tokens::token tok; + std::vector 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 }); + } + print("Nested ok!"); + c->args.push(tempval); } - else if (tempstream.match(tokens::seperator)) { - // We have a seperator for function arguments - tempstream.next(); // Consume it + else if (tempstream.match(tokens::name)) { + cleanup(tempval); + tempval = buildVariable(tempstream.next().name); + c->args.push(tempval); + } + 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 + return true; + } + else { + cleanup(tempval); // Cleanup + state->push_error(errors::error{ errors::badtoken,concat("Invalid symbol: ",tempstream.peek()),true, tempstream.peek().line_num}); } } - /*std::cout << "---Tokens---" << std::endl; - for (size_t i = 0; i < t.size() - 1; i++) { - std::cout << t[i] << std::endl; - }*/ - current_chunk->addCmd(c); // We push this onto the chunk after all dependants if any have been handled - wait(); } 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(); - 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! - } - else if (t.type == tokens::number) { + 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,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! } } - } } \ No newline at end of file diff --git a/DMS/LineParserParse.cpp b/DMS/LineParserParse.cpp index 0c705f6..9a7b01a 100644 --- a/DMS/LineParserParse.cpp +++ b/DMS/LineParserParse.cpp @@ -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(); - } - 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 }); - } - } + //token control = stream.next(); + if (match_process_choice(&stream)) { + // Handle choice stuff } - else if (control.raw == codes::IFFF) { + else if (match_process_IFFF(&stream)) { // This will probably be the toughest one of them all } } diff --git a/DMS/LineParserUtils.cpp b/DMS/LineParserUtils.cpp index 7624c8d..a302b0e 100644 --- a/DMS/LineParserUtils.cpp +++ b/DMS/LineParserUtils.cpp @@ -6,6 +6,9 @@ namespace dms { void tokenstream::init(std::vector* 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 }; diff --git a/DMS/dump.txt b/DMS/dump.txt index 4b7e7bf..a614711 100644 --- a/DMS/dump.txt +++ b/DMS/dump.txt @@ -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 diff --git a/DMS/errors.h b/DMS/errors.h index ee64292..d179a10 100644 --- a/DMS/errors.h +++ b/DMS/errors.h @@ -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; diff --git a/DMS/test.dms b/DMS/test.dms index 917b585..9783cfe 100644 --- a/DMS/test.dms +++ b/DMS/test.dms @@ -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 diff --git a/DMS/value.cpp b/DMS/value.cpp index 81c616f..ce2aebd 100644 --- a/DMS/value.cpp +++ b/DMS/value.cpp @@ -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)); diff --git a/DMS/value.h b/DMS/value.h index eb72bff..f0aeb0b 100644 --- a/DMS/value.h +++ b/DMS/value.h @@ -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);