diff --git a/DMS/DMS.vcxproj b/DMS/DMS.vcxproj
index b188331..81d8d24 100644
--- a/DMS/DMS.vcxproj
+++ b/DMS/DMS.vcxproj
@@ -147,10 +147,11 @@
-
+
+
-
+
diff --git a/DMS/DMS.vcxproj.filters b/DMS/DMS.vcxproj.filters
index af03e5d..1dcf68d 100644
--- a/DMS/DMS.vcxproj.filters
+++ b/DMS/DMS.vcxproj.filters
@@ -30,9 +30,6 @@
Source Files\DMS
-
- Source Files\DMS
-
Source Files\DMS
@@ -54,7 +51,13 @@
Source Files\DMS
-
+
+ Source Files\DMS
+
+
+ Source Files\DMS
+
+
Source Files\DMS
diff --git a/DMS/LineParser.h b/DMS/LineParser.h
index 0ed5c01..c8e9788 100644
--- a/DMS/LineParser.h
+++ b/DMS/LineParser.h
@@ -29,6 +29,10 @@ namespace dms {
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);
bool hasScope(size_t tabs);
+ bool restore(size_t p) {
+ pos = p;
+ return false; // This is a convience for something I will be doing so much
+ }
};
struct passer {
std::string stream;
@@ -51,16 +55,28 @@ namespace dms {
std::vector temp;
size_t tabs = 0;
dms_state* state;
-
+ void doCheck(passer* stream, std::vector* t_vec, size_t line, bool& isNum, bool& hasDec, std::vector* buffer);
void _Parse(tokenstream stream);
// Match Process Code
bool match_process_debug(tokenstream* stream);
bool match_process_disp(tokenstream* stream);
bool match_process_choice(tokenstream* stream);
- bool match_process_function(tokenstream* stream);
+ bool match_process_function(tokenstream* stream, value* v=nullptr);
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);
+ // 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);
+ tokens::tokentype* expr();
+ tokens::tokentype* variable();
+ void tokenizer(dms_state* state, std::vector &tok);
public:
//Refer to streams.cpp for the match_process_CMD code.
dms_state* Parse();
@@ -68,23 +84,5 @@ namespace dms {
dms_state* Parse(dms_state* state, std::string l);
LineParser(std::string fn);
LineParser();
- //Matches tokens from the stream, if the tokens match it will return true and YOU should call next on the stream. This method does not change the current position
-
- bool createBlock(std::string bk_name, blocktype bk_type);
- bool buildLabel(chunk c, std::string label);
-
- bool processFunc(tokenstream stream, chunk c);
- bool processFunc(tokenstream stream, chunk c, std::string gotoo);
- bool processExpr(tokenstream stream, chunk c);
- bool processLogic(tokenstream stream, chunk c);
-
- //Utils
- bool isBlock();
- bool isBlock(blocktype bk_type);
-
- void tolower(std::string &str);
- tokens::tokentype* expr();
- tokens::tokentype* variable();
- void tokenizer(dms_state* state, std::vector &tok);
};
}
\ No newline at end of file
diff --git a/DMS/LineParserExtended.cpp b/DMS/LineParserExtended.cpp
deleted file mode 100644
index 1fd11d8..0000000
--- a/DMS/LineParserExtended.cpp
+++ /dev/null
@@ -1,63 +0,0 @@
-#include "LineParser.h"
-using namespace dms::tokens;
-using namespace dms::utils;
-namespace dms {
- bool LineParser::match_process_disp(tokenstream* stream) {
- /*
- DISP, "msg"
- DISP, "msg" speaker
-
- Compound DISP
- */
- if (isBlock(bt_block) && stream->match(tokens::newline, tokens::string, tokens::newline)) {
- stream->next(); // Standard consumption
- std::string msg = stream->next().name;
- print("DISP := ", msg);
- cmd* c = new cmd;
- c->opcode = codes::DISP;
- c->args.push(buildValue(msg));
- current_chunk->addCmd(c); // Add the cmd to the current chunk
- return true;
- }
- else if (isBlock(bt_block) && stream->match(tokens::newline, tokens::name, tokens::colon, tokens::string, tokens::newline)) {
- // We might have to handle scope here
- // Here we match 'Ryan: "This guy said this!"' Note the colon is needed!
- stream->next(); // Standard consumption
- std::string name = stream->next().name;
- stream->next(); // That colon
- std::string msg = stream->next().name;
- print("DISP := ", name, " says '", msg, "'");
- cmd* c = new cmd;
- c->opcode = codes::DISP;
- c->args.push(buildValue(msg));
- c->args.push(buildValue(name));
- current_chunk->addCmd(c); // Add the cmd to the current chunk
- // We might have to consume a newline... Depends on what's next
- return true;
- }
- // emotion: "path"
- // looks like a simple disp command
- else if (isBlock(bt_character) && stream->match(tokens::tab, tokens::name, tokens::colon, tokens::string, tokens::newline)) {
- return true;
- }
- return false;
- }
- bool LineParser::match_process_debug(tokenstream* stream) {
- return false;
- }
- bool LineParser::match_process_choice(tokenstream* stream) {
- return false;
- }
- bool LineParser::match_process_function(tokenstream* stream) {
- return false;
- }
- bool LineParser::match_process_goto(tokenstream* stream) {
- return false;
- }
- bool LineParser::match_process_jump(tokenstream* stream) {
- return false;
- }
- bool LineParser::match_process_exit(tokenstream* stream) {
- return false;
- }
-}
\ No newline at end of file
diff --git a/DMS/LineParserMatchProcess.cpp b/DMS/LineParserMatchProcess.cpp
new file mode 100644
index 0000000..aa16574
--- /dev/null
+++ b/DMS/LineParserMatchProcess.cpp
@@ -0,0 +1,183 @@
+#include "LineParser.h"
+using namespace dms::tokens;
+using namespace dms::utils;
+namespace dms {
+ bool LineParser::match_process_disp(tokenstream* stream) {
+ /*
+ DISP, "msg"
+ DISP, "msg" speaker
+
+ Compound DISP
+ */
+ if (isBlock(bt_block) && stream->match(tokens::newline, tokens::string, tokens::newline)) {
+ stream->next(); // Standard consumption
+ std::string msg = stream->next().name;
+ print("DISP := ", msg);
+ cmd* c = new cmd;
+ c->opcode = codes::DISP;
+ c->args.push(buildValue(msg));
+ current_chunk->addCmd(c); // Add the cmd to the current chunk
+ return true;
+ }
+ else if (isBlock(bt_block) && stream->match(tokens::newline, tokens::name, tokens::colon, tokens::string, tokens::newline)) {
+ // We might have to handle scope here
+ // Here we match 'Ryan: "This guy said this!"' Note the colon is needed!
+ stream->next(); // Standard consumption
+ std::string name = stream->next().name;
+ stream->next(); // That colon
+ std::string msg = stream->next().name;
+ print("DISP := ", name, " says '", msg, "'");
+ cmd* c = new cmd;
+ c->opcode = codes::DISP;
+ c->args.push(buildValue(msg));
+ c->args.push(buildValue(name));
+ current_chunk->addCmd(c); // Add the cmd to the current chunk
+ // We might have to consume a newline... Depends on what's next
+ return true;
+ }
+ // emotion: "path"
+ // looks like a simple disp command
+ else if (isBlock(bt_character) && stream->match(tokens::tab, tokens::name, tokens::colon, tokens::string, tokens::newline)) {
+ return true;
+ }
+
+ // TODO: We still have to implement the compound disp
+
+ return false;
+ }
+ bool LineParser::match_process_debug(tokenstream* stream) {
+ return false;
+ }
+ bool LineParser::match_process_choice(tokenstream* stream) {
+ return false;
+ }
+ ///
+ /// Recursively parse through function related tokens
+ ///
+ ///
+ ///
+ ///
+ bool LineParser::match_process_function(tokenstream* stream, value* v) {
+ /*
+ 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!
+
+ The bytecode here is a little tricky, a bit of moving parts and work that the vm has to do.
+
+ If a function has a return that is expected to be consumed, v will not be nullptr and will be pointing to something
+ The type of v should be variable and if not throw an error!
+
+ The bytecode should look something like this for a given method:
+ testfunc("Hello!")
+ off op opcode
+ 0 FUNC testfunc "Hello"
+
+ The bytecode should look something like this for a given method:
+ val = testfunc2(2,2)
+ off op opcode
+ 0 FUNC testfunc2 val 2 2
+
+ Notice how we have nil for the first function with no return, this tells the interperter that we do not need to store a value at all
+ The second method has a varaible to store val so we store that in val
+
+ Given a function:
+ val = test3(testfunc2(4,4),"Test function as an argument!")
+ off op opcode
+ 0 FUNC testfunc2 $A 4 4
+ 1 FUNC test3 val $A "Test function as an argument!"
+
+ Not too scary, in fact it's rathar stright forward
+ Last example:
+ test4("Testing",test3(1,testfunc2(1,2)),testfunc2(10,100))
+ off op opcode
+ 0 FUNC testfunc2 $A 1 2
+ 1 FUNC test3 $B 1 $A
+ 2 FUNC testfunc2 $C 10 100
+ 3 FUNC test4 nil "Testing" $B $C
+
+ A bit more involved, but I'm sure it wasn't too much to follow, especially if you looked at the examples in order
+
+ That's all there is to functions within the bytecode side of things, the vm is where things are a little more involved
+ */
+ if (stream->match(tokens::name, tokens::parao)) {
+ cmd* c = new cmd;
+ c->opcode = codes::FUNC;
+ std::string n = stream->next().name;
+ print("FUNC ",n);
+ c->args.push(buildValue(n)); // Set the func identifier as the first variable
+ // Let's set the target
+ if (v != nullptr) {
+ c->args.push(v); // Push the supplied variable
+ }
+ else {
+ c->args.push(buildValue()); // Creates a nil value
+ }
+ // Already we have built: FUNC name val
+ // 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;
+ while (tempstream.peek().type != tokens::none) { // End of stream
+ if (tempstream.match(tokens::string)) {
+ // We have a string argument
+ }
+ else if (tempstream.match(tokens::number)) {
+ // This is an interesting one This could be just a number, or an expression with functions n stuff
+ }
+ else if (match_process_expression(&tempstream)) {
+ // 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 (tempstream.match(tokens::seperator)) {
+ // We have a seperator for function arguments
+ tempstream.next(); // Consume it
+ }
+ }
+ /*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;
+ }
+ bool LineParser::match_process_goto(tokenstream* stream) {
+ return false;
+ }
+ bool LineParser::match_process_jump(tokenstream* stream) {
+ return false;
+ }
+ bool LineParser::match_process_exit(tokenstream* stream) {
+ return false;
+ }
+ bool LineParser::match_process_label(tokenstream* stream) {
+ return false;
+ }
+ bool LineParser::match_process_expression(tokenstream* stream) {
+ // 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) {
+
+ }
+ }
+ 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/LineParser.cpp b/DMS/LineParserParse.cpp
similarity index 69%
rename from DMS/LineParser.cpp
rename to DMS/LineParserParse.cpp
index 2f5dc62..0c705f6 100644
--- a/DMS/LineParser.cpp
+++ b/DMS/LineParserParse.cpp
@@ -3,430 +3,6 @@
using namespace dms::tokens;
using namespace dms::utils;
namespace dms {
- void tokenstream::init(std::vector* ptr) {
- this->tokens = *ptr;
- }
- token tokenstream::next() {
- if (pos > this->tokens.size())
- return token{ tokentype::noop,codes::NOOP,"EOF",0 };
- return this->tokens[pos++];
- }
- void tokenstream::prev() {
- pos--;
- }
- std::vector tokenstream::next(tokentype to, tokentype tc) {
- std::vector tok;
- size_t open = 0;
- if (peek().type == to) {
- open++;
- next(); // Consume
- while (open != 0) {
- if (peek().type == to)
- open++;
- else if (peek().type == tc)
- open--;
- tok.push_back(next());
- }
- }
- return tok;
- }
- token tokenstream::peek() {
- return this->tokens[pos];
- }
- bool tokenstream::hasScope(size_t tabs) {
- return false;
- }
- std::vector tokenstream::next(tokentype tk) {
- std::vector temp;
- while (peek().type!=tk) {
- temp.push_back(next());
- }
- temp.push_back(next());
- return temp;
- }
- uint8_t passer::next() {
- if (stream.size() == pos) {
- return NULL;
- }
- else {
- return stream[pos++];
- }
- }
- void passer::next(uint8_t c) {
- next();
- while (peek() != c) {
- next();
- }
- }
- uint8_t passer::prev() {
- if (0 == pos) {
- return NULL;
- }
- return stream[--pos];
- }
- uint8_t passer::peek() {
- if (stream.size() == pos) {
- return NULL;
- }
- return stream[pos];
- }
- std::string passer::processBuffer(std::vector buf) {
- return std::string(buf.begin(), buf.end());
- }
- bool LineParser::isBlock() {
- return isBlock(bt_block); // Default block type
- }
- bool LineParser::isBlock(blocktype bk_type) {
- if (current_chunk == nullptr) {
- return false; // If a chunk wasn't defined then code was probably defined outside of a block
- }
- return current_chunk->type == bk_type;
- }
- void doCheck(passer* stream,std::vector* t_vec, size_t line, bool &isNum, bool &hasDec, std::vector* buffer) {
- std::string str = stream->processBuffer(*buffer);
- if (utils::isNum(str) && isNum) {
- t_vec->push_back(token{ tokens::number,codes::NOOP,stream->processBuffer(*buffer),line });
- buffer->clear();
- isNum = false;
- hasDec = false;
- }
- else if (buffer->size() > 0) {
- if (str == "nil") {
- t_vec->push_back(token{ tokens::nil,codes::NOOP,stream->processBuffer(*buffer),line });
- buffer->clear();
- hasDec = false;
- }
- else if (str == "true") {
- t_vec->push_back(token{ tokens::True,codes::NOOP,stream->processBuffer(*buffer),line });
- buffer->clear();
- hasDec = false;
- }
- else if (str == "false") {
- t_vec->push_back(token{ tokens::False,codes::NOOP,stream->processBuffer(*buffer),line });
- buffer->clear();
- hasDec = false;
- }
- else if (utils::isNum(str) && str.size() > 0) {
- t_vec->push_back(token{ tokens::number,codes::NOOP,stream->processBuffer(*buffer),line });
- buffer->clear();
- isNum = false;
- hasDec = false;
- }
- else if (utils::isalphanum(str) && str.size() > 0) {
- t_vec->push_back(token{ tokens::name,codes::NOOP,stream->processBuffer(*buffer),line });
- buffer->clear();
- hasDec = false;
- }
- else {
- t_vec->push_back(token{ tokens::name,codes::ERRO,"Invalid variable name!",line });
- }
- }
- }
- void wait() {
- std::cin.ignore();
- }
- bool tokenstream::match(tokens::tokentype t1, tokens::tokentype t2, tokens::tokentype t3, tokens::tokentype t4, tokens::tokentype t5, tokens::tokentype t6, tokens::tokentype t7, tokens::tokentype t8, tokens::tokentype t9, tokens::tokentype t10, tokens::tokentype t11, tokens::tokentype t12) {
- tokens::tokentype types[12] = { t1,t2,t3,t4,t5,t6,t7,t8,t9,t10,t11,t12 };
- for (size_t i = 0; i < 12; i++) {
- if (types[i] == tokens::none)
- return true;
- if (this->tokens[pos+i].type != types[i])
- return false;
- }
- return true;
- }
- tokentype* LineParser::expr() {
- return new tokentype[9]{ tokens::name,tokens::number,tokens::divide,tokens::minus,tokens::mod,tokens::multiply,tokens::plus,tokens::pow ,tokens::none };
- // tokens::none tells us we are at the end of the array.
- }
- tokentype* LineParser::variable() {
- return new tokentype[7]{tokens::name,tokens::number,tokens::True,tokens::False,tokens::nil,tokens::string,tokens::none};
- // tokens::none tells us we are at the end of the array.
- }
- bool inList(tokens::tokentype t,tokens::tokentype* list) {
- size_t c = 0;
- while (list[c] != tokens::none) {
- if (list[c] == t)
- return true;
- }
- return false;
- }
- bool tokenstream::match(tokens::tokentype* t1, tokens::tokentype* t2, tokens::tokentype* t3, tokens::tokentype* t4, tokens::tokentype* t5, tokens::tokentype* t6, tokens::tokentype* t7, tokens::tokentype* t8, tokens::tokentype* t9, tokens::tokentype* t10, tokens::tokentype* t11, tokens::tokentype* t12) {
- tokens::tokentype* types[12] = { t1,t2,t3,t4,t5,t6,t7,t8,t9,t10,t11,t12 };
- for (size_t i = 0; i < 12; i++) {
- if (types[i] == nullptr)
- return true;
- if (!inList(this->tokens[pos + i].type, types[i]))
- return false;
- }
- return true;
- }
-
- // Handling functions are important. This method is a helper function that allows you to
- bool LineParser::processFunc(tokenstream stream, chunk c) {
- //
- return false;
- }
- bool processFunc(tokenstream stream, chunk c, std::string gotoo) {
- return true;
- }
- bool LineParser::processExpr(tokenstream stream, chunk c) {
- //
- return false;
- }
- bool LineParser::processLogic(tokenstream stream, chunk c) {
- //
- return false;
- }
- bool LineParser::createBlock(std::string bk_name, blocktype bk_type) {
- if (current_chunk != nullptr) {
- if (!state->chunks.count(current_chunk->name))
- state->chunks.insert_or_assign(current_chunk->name, current_chunk);
- else
- {
- std::stringstream str;
- str << "Block <" << current_chunk->name << "> already defined!";
- state->push_error(errors::error{ errors::block_already_defined,str.str(),true,line });
- return false;
- }
- }
- current_chunk = new chunk;
- current_chunk->name = bk_name;
- chunk_type = bk_type;
- current_chunk->type = bk_type;
- print("Created Block: ",bk_name," <",bk_type,">");
- return true;
- }
- void LineParser::_Parse(tokenstream stream) {
- token current = stream.next();
- while (stream.peek().type != tokens::eof) {
- print(current);
- if (current.type == tokens::flag) {
- temp = stream.next(tokens::newline);
- stream.prev(); // Unconsume the newline piece
- if (temp.size() != 2) {
- std::cout << "Error";
- }
- codes::op code = current.raw;
- tokens::tokentype tok = temp[0].type;
- if (code == codes::ENAB && tok == tokens::name) {
- tolower(temp[0].name);
- state->enables.insert_or_assign(temp[0].name, true);
- }
- else if (code == codes::ENTR && tok == tokens::name) {
- state->entry = temp[0].name;
- }
- else if (code == codes::DISA && tok == tokens::name) {
- tolower(temp[0].name);
- state->enables.insert_or_assign(temp[0].name, false);
- }
- else if (code == codes::VERN && tok == tokens::number) {
- state->version = std::stod(temp[0].name);
- }
- else if (code == codes::USIN && tok == tokens::name) {
- // TODO add usings, kinda useless atm since everything will be packed in. Perhaps extensions?
- }
- else if (code == codes::LOAD && tok == tokens::string) {
- print("Loading File: ",temp[0].name);
- LineParser parser = LineParser();
- parser.Parse(state, temp[0].name);// Load another file
- }
- else {
- std::stringstream str;
- str << "Expected " << " got: " << current << temp[0];
- state->push_error(errors::error{ errors::badtoken,str.str(),true,line });
- }
- }
- // Default block
- if (stream.match(tokens::newline, tokens::bracketo, tokens::name, tokens::bracketc)) {
- stream.next();
- std::string name = stream.next().name;
- createBlock(name,bt_block);
- line = stream.next().line_num; // Consume
- }
- // This handles a few block types since they all follow a similar format
- else if (stream.match(tokens::newline, tokens::bracketo, tokens::name, tokens::colon, tokens::name, tokens::bracketc)) {
- stream.next();
- stream.next();
- std::string name = stream.next().name;
- line = stream.next().line_num;
- std::string temp = stream.next().name;
- // Characters are a feature I want to have intergrated into the language
- if (temp == "char") {
- createBlock(name, bt_character);
- }
- // Enviroments are sortof like objects, they can be uses as an object. They are a cleaner way to build a hash map like object
- else if (temp == "env") {
- createBlock(name, bt_env);
- }
- // Menus are what they say on the tin. They provide the framework for having menus within your game
- else if (temp == "menu") {
- createBlock(name, bt_menu);
- }
- }
- // Function block type
- else if (stream.match(tokens::newline, tokens::bracketo, tokens::name, tokens::colon, tokens::name, tokens::parao)) {
- std::stringstream str;
- stream.next();
- stream.next();
- std::string name = stream.next().name;
- line = stream.next().line_num; // The color, not needed after the inital match, but we still need to consume it
- std::string b = stream.next().name;
- if (b == "function") {
- createBlock(name, bt_method); // We have a method let's set the block type to that, but we aren't done yet
- // We need to set the params if any so the method can be supplied with arguments
- stream.next(); // parao
- std::vector tokens = stream.next(tokens::parac); // Consume until we see parac
- dms_args args;
- for (size_t i = 0; i < tokens.size() - 1; i++) {//The lase symbol is parac since that was the consume condition
- if (tokens[i].type == tokens::name) {
- // We got a name which is refering to a variable so lets build one
- value* v = new value{};
- v->type = datatypes::variable; // Special type, it writes data to the string portion, but is interperted as a lookup
- v->s = buildString(tokens[i].name);
- args.push(v);
- }
- else if (tokens[i].type == tokens::seperator) {
- // We just ignore this
- }
- else {
- std::stringstream str;
- str << "Unexpected symbol: " << tokens[i];
- state->push_error(errors::error{ errors::badtoken,str.str(),true,line });
- }
- }
- // If all went well the 'args' now has all of tha params for the method we will be working with
- current_chunk->params = args;
- // Thats should be all we need to do
- }
- else {
- str << "'function' keyword expected got " << b;
- state->push_error(errors::error{ errors::badtoken, str.str(),true,line });
- }
- }
- // 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
-
- /*
- 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::string)) {
- std::string name = stream.next().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,"Unexpected symbol!"});
- }
- }
- }
- else if (control.raw == codes::IFFF) {
- // This will probably be the toughest one of them all
- }
- }
- // Displays both with a target and without
- match_process_disp(&stream);
-
- // function stuff
- /*if (match(stream, tokens::name, tokens::parao)) {
- std::string n = stream.next().name;
- std::vector t = stream.next(tokens::parao, tokens::parac);
- std::cout << "---Tokens---" << std::endl;
- for (size_t i = 0; i < t.size()-1; i++) {
- std::cout << t[i] << std::endl;
- }
- wait();
- }*/
- if (current.type != tokens::tab)
- tabs = 0;
- current = stream.next();
- }
- state->chunks.insert_or_assign(current_chunk->name, current_chunk);
- }
- void LineParser::tokenizer(dms_state* state,std::vector &toks) {
- tokenstream stream;
- stream.init(&toks);
- this->state = state; // Grab the pointer to the state and store it within the parser object
- _Parse(stream);
- }
- void LineParser::tolower(std::string &s1) {
- std::transform(s1.begin(), s1.end(), s1.begin(), std::tolower);
- }
- LineParser::LineParser(std::string f) {
- fn = f;
- }
- LineParser::LineParser() {}
dms_state* dms::LineParser::Parse() {
if (fn == "") {
std::cout << "ERROR: You did not provide the constructor with a file path!" << std::endl;
@@ -439,7 +15,7 @@ namespace dms {
return Parse(state, fn);
}
dms_state* dms::LineParser::Parse(dms_state* state, std::string file) {
- std::map chunks;
+ std::unordered_map chunks;
std::vector t_vec;
std::string li;
std::ifstream myfile(file);
@@ -471,11 +47,11 @@ namespace dms {
bool hasDec = false;
bool labelStart = false;
size_t line = 1;
- while (data != NULL) {
- if (data == '/' && stream.peek()=='/') {
+ while (data != NULL) {
+ if (data == '/' && stream.peek() == '/') {
//line++;
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 });
@@ -489,8 +65,8 @@ namespace dms {
}
else if (data == '"' && !isStr) {
isStr = true;
- }
- else if (data == ':' && stream.peek()==':' && !labelStart) {
+ }
+ else if (data == ':' && stream.peek() == ':' && !labelStart) {
labelStart = true;
stream.next();
}
@@ -509,7 +85,7 @@ namespace dms {
t_vec.push_back(token{ tokens::string,codes::NOOP,stream.processBuffer(buffer),line });
buffer.clear();
}
- else if (isdigit(data) ) {
+ else if (isdigit(data)) {
isNum = true;
buffer.push_back(data);
}
@@ -605,7 +181,8 @@ namespace dms {
tolower(str);
if (str == "enable") {
t_vec.push_back(token{ tokens::flag,codes::ENAB,"",line });
- } else if (str == "entry") {
+ }
+ else if (str == "entry") {
t_vec.push_back(token{ tokens::flag,codes::ENTR,"",line });
}
else if (str == "loadfile") {
@@ -662,7 +239,10 @@ namespace dms {
else if (str == "jump") {
t_vec.push_back(token{ tokens::jump,codes::NOOP,"",line });
}
- else if (utils::isalphanum(str) && str.size()>0) {
+ else if (str == "exit") {
+ t_vec.push_back(token{ tokens::exit,codes::NOOP,"",line });
+ }
+ else if (utils::isalphanum(str) && str.size() > 0) {
t_vec.push_back(token{ tokens::name,codes::NOOP,stream.processBuffer(buffer),line });
}
else {
@@ -674,8 +254,8 @@ namespace dms {
buffer.clear();
}
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++) {
@@ -687,4 +267,219 @@ namespace dms {
tokenizer(state, t_vec);
return state;
}
+ void LineParser::_Parse(tokenstream stream) {
+ token current = stream.next();
+ while (stream.peek().type != tokens::eof) {
+ print(current);
+ if (current.type == tokens::flag) {
+ temp = stream.next(tokens::newline);
+ stream.prev(); // Unconsume the newline piece
+ if (temp.size() != 2) {
+ std::cout << "Error";
+ }
+ codes::op code = current.raw;
+ tokens::tokentype tok = temp[0].type;
+ if (code == codes::ENAB && tok == tokens::name) {
+ tolower(temp[0].name);
+ state->enables.insert_or_assign(temp[0].name, true);
+ }
+ else if (code == codes::ENTR && tok == tokens::name) {
+ state->entry = temp[0].name;
+ }
+ else if (code == codes::DISA && tok == tokens::name) {
+ tolower(temp[0].name);
+ state->enables.insert_or_assign(temp[0].name, false);
+ }
+ else if (code == codes::VERN && tok == tokens::number) {
+ state->version = std::stod(temp[0].name);
+ }
+ else if (code == codes::USIN && tok == tokens::name) {
+ // TODO add usings, kinda useless atm since everything will be packed in. Perhaps extensions?
+ }
+ else if (code == codes::LOAD && tok == tokens::string) {
+ print("Loading File: ", temp[0].name);
+ LineParser parser = LineParser();
+ parser.Parse(state, temp[0].name);// Load another file
+ }
+ else {
+ std::stringstream str;
+ str << "Expected " << " got: " << current << temp[0];
+ state->push_error(errors::error{ errors::badtoken,str.str(),true,line });
+ }
+ }
+ // Default block
+ if (stream.match(tokens::newline, tokens::bracketo, tokens::name, tokens::bracketc)) {
+ stream.next();
+ std::string name = stream.next().name;
+ createBlock(name, bt_block);
+ line = stream.next().line_num; // Consume
+ }
+ // This handles a few block types since they all follow a similar format
+ else if (stream.match(tokens::newline, tokens::bracketo, tokens::name, tokens::colon, tokens::name, tokens::bracketc)) {
+ stream.next();
+ stream.next();
+ std::string name = stream.next().name;
+ line = stream.next().line_num;
+ std::string temp = stream.next().name;
+ // Characters are a feature I want to have intergrated into the language
+ if (temp == "char") {
+ createBlock(name, bt_character);
+ }
+ // Enviroments are sortof like objects, they can be uses as an object. They are a cleaner way to build a hash map like object
+ else if (temp == "env") {
+ createBlock(name, bt_env);
+ }
+ // Menus are what they say on the tin. They provide the framework for having menus within your game
+ else if (temp == "menu") {
+ createBlock(name, bt_menu);
+ }
+ }
+ // Function block type
+ else if (stream.match(tokens::newline, tokens::bracketo, tokens::name, tokens::colon, tokens::name, tokens::parao)) {
+ std::stringstream str;
+ stream.next();
+ stream.next();
+ std::string name = stream.next().name;
+ line = stream.next().line_num; // The color, not needed after the inital match, but we still need to consume it
+ std::string b = stream.next().name;
+ if (b == "function") {
+ createBlock(name, bt_method); // We have a method let's set the block type to that, but we aren't done yet
+ // We need to set the params if any so the method can be supplied with arguments
+ stream.next(); // parao
+ std::vector tokens = stream.next(tokens::parac); // Consume until we see parac
+ dms_args args;
+ for (size_t i = 0; i < tokens.size() - 1; i++) {//The lase symbol is parac since that was the consume condition
+ if (tokens[i].type == tokens::name) {
+ // We got a name which is refering to a variable so lets build one
+ value* v = new value{};
+ v->type = datatypes::variable; // Special type, it writes data to the string portion, but is interperted as a lookup
+ v->s = buildString(tokens[i].name);
+ args.push(v);
+ }
+ else if (tokens[i].type == tokens::seperator) {
+ // We just ignore this
+ }
+ else {
+ std::stringstream str;
+ str << "Unexpected symbol: " << tokens[i];
+ state->push_error(errors::error{ errors::badtoken,str.str(),true,line });
+ }
+ }
+ // If all went well the 'args' now has all of tha params for the method we will be working with
+ current_chunk->params = args;
+ // Thats should be all we need to do
+ }
+ else {
+ str << "'function' keyword expected got " << b;
+ state->push_error(errors::error{ errors::badtoken, str.str(),true,line });
+ }
+ }
+ // 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 });
+ }
+ }
+ }
+ else if (control.raw == codes::IFFF) {
+ // This will probably be the toughest one of them all
+ }
+ }
+ // Displays both with a target and without
+ match_process_disp(&stream);
+
+ if (current.type != tokens::tab)
+ tabs = 0;
+ current = stream.next();
+ }
+ state->chunks.insert_or_assign(current_chunk->name, current_chunk);
+ }
}
\ No newline at end of file
diff --git a/DMS/LineParserUtils.cpp b/DMS/LineParserUtils.cpp
new file mode 100644
index 0000000..7624c8d
--- /dev/null
+++ b/DMS/LineParserUtils.cpp
@@ -0,0 +1,195 @@
+#include "LineParser.h"
+#include "errors.h"
+using namespace dms::tokens;
+using namespace dms::utils;
+namespace dms {
+ void tokenstream::init(std::vector* ptr) {
+ this->tokens = *ptr;
+ }
+ token tokenstream::next() {
+ if (pos > this->tokens.size())
+ return token{ tokentype::none,codes::NOOP,"EOS",0 };
+ return this->tokens[pos++];
+ }
+ void tokenstream::prev() {
+ pos--;
+ }
+ std::vector tokenstream::next(tokentype to, tokentype tc) {
+ std::vector tok;
+ size_t open = 0;
+ if (peek().type == to) {
+ open++;
+ next(); // Consume
+ while (open != 0) {
+ if (peek().type == to)
+ open++;
+ else if (peek().type == tc)
+ open--;
+ tok.push_back(next());
+ }
+ }
+ return tok;
+ }
+ token tokenstream::peek() {
+ if (pos > this->tokens.size())
+ return token{ tokentype::none,codes::NOOP,"EOS",0 };
+ return this->tokens[pos];
+ }
+ bool tokenstream::hasScope(size_t tabs) {
+ return false;
+ }
+ std::vector tokenstream::next(tokentype tk) {
+ std::vector temp;
+ while (peek().type!=tk) {
+ temp.push_back(next());
+ }
+ temp.push_back(next());
+ return temp;
+ }
+ uint8_t passer::next() {
+ if (stream.size() == pos) {
+ return NULL;
+ }
+ else {
+ return stream[pos++];
+ }
+ }
+ void passer::next(uint8_t c) {
+ next();
+ while (peek() != c) {
+ next();
+ }
+ }
+ uint8_t passer::prev() {
+ if (0 == pos) {
+ return NULL;
+ }
+ return stream[--pos];
+ }
+ uint8_t passer::peek() {
+ if (stream.size() == pos) {
+ return NULL;
+ }
+ return stream[pos];
+ }
+ std::string passer::processBuffer(std::vector buf) {
+ return std::string(buf.begin(), buf.end());
+ }
+ bool LineParser::isBlock() {
+ return isBlock(bt_block); // Default block type
+ }
+ bool LineParser::isBlock(blocktype bk_type) {
+ if (current_chunk == nullptr) {
+ return false; // If a chunk wasn't defined then code was probably defined outside of a block
+ }
+ return current_chunk->type == bk_type;
+ }
+ bool tokenstream::match(tokens::tokentype t1, tokens::tokentype t2, tokens::tokentype t3, tokens::tokentype t4, tokens::tokentype t5, tokens::tokentype t6, tokens::tokentype t7, tokens::tokentype t8, tokens::tokentype t9, tokens::tokentype t10, tokens::tokentype t11, tokens::tokentype t12) {
+ tokens::tokentype types[12] = { t1,t2,t3,t4,t5,t6,t7,t8,t9,t10,t11,t12 };
+ for (size_t i = 0; i < 12; i++) {
+ if (types[i] == tokens::none)
+ return true;
+ if (this->tokens[pos+i].type != types[i])
+ return false;
+ }
+ return true;
+ }
+ tokentype* LineParser::expr() {
+ return new tokentype[9]{ tokens::name,tokens::number,tokens::divide,tokens::minus,tokens::mod,tokens::multiply,tokens::plus,tokens::pow ,tokens::none };
+ // tokens::none tells us we are at the end of the array.
+ }
+ tokentype* LineParser::variable() {
+ return new tokentype[7]{tokens::name,tokens::number,tokens::True,tokens::False,tokens::nil,tokens::string,tokens::none};
+ // tokens::none tells us we are at the end of the array.
+ }
+ bool inList(tokens::tokentype t,tokens::tokentype* list) {
+ size_t c = 0;
+ while (list[c] != tokens::none) {
+ if (list[c] == t)
+ return true;
+ }
+ return false;
+ }
+ bool tokenstream::match(tokens::tokentype* t1, tokens::tokentype* t2, tokens::tokentype* t3, tokens::tokentype* t4, tokens::tokentype* t5, tokens::tokentype* t6, tokens::tokentype* t7, tokens::tokentype* t8, tokens::tokentype* t9, tokens::tokentype* t10, tokens::tokentype* t11, tokens::tokentype* t12) {
+ tokens::tokentype* types[12] = { t1,t2,t3,t4,t5,t6,t7,t8,t9,t10,t11,t12 };
+ for (size_t i = 0; i < 12; i++) {
+ if (types[i] == nullptr)
+ return true;
+ if (!inList(this->tokens[pos + i].type, types[i]))
+ return false;
+ }
+ return true;
+ }
+ void LineParser::doCheck(passer* stream, std::vector* t_vec, size_t line, bool& isNum, bool& hasDec, std::vector* buffer) {
+ std::string str = stream->processBuffer(*buffer);
+ if (utils::isNum(str) && isNum) {
+ t_vec->push_back(token{ tokens::number,codes::NOOP,stream->processBuffer(*buffer),line });
+ buffer->clear();
+ isNum = false;
+ hasDec = false;
+ }
+ else if (buffer->size() > 0) {
+ if (str == "nil") {
+ t_vec->push_back(token{ tokens::nil,codes::NOOP,stream->processBuffer(*buffer),line });
+ buffer->clear();
+ hasDec = false;
+ }
+ else if (str == "true") {
+ t_vec->push_back(token{ tokens::True,codes::NOOP,stream->processBuffer(*buffer),line });
+ buffer->clear();
+ hasDec = false;
+ }
+ else if (str == "false") {
+ t_vec->push_back(token{ tokens::False,codes::NOOP,stream->processBuffer(*buffer),line });
+ buffer->clear();
+ hasDec = false;
+ }
+ else if (utils::isNum(str) && str.size() > 0) {
+ t_vec->push_back(token{ tokens::number,codes::NOOP,stream->processBuffer(*buffer),line });
+ buffer->clear();
+ isNum = false;
+ hasDec = false;
+ }
+ else if (utils::isalphanum(str) && str.size() > 0) {
+ t_vec->push_back(token{ tokens::name,codes::NOOP,stream->processBuffer(*buffer),line });
+ buffer->clear();
+ hasDec = false;
+ }
+ else {
+ t_vec->push_back(token{ tokens::name,codes::ERRO,"Invalid variable name!",line });
+ }
+ }
+ }
+ bool LineParser::createBlock(std::string bk_name, blocktype bk_type) {
+ if (current_chunk != nullptr) {
+ if (!state->chunks.count(current_chunk->name))
+ state->chunks.insert_or_assign(current_chunk->name, current_chunk);
+ else
+ {
+ std::stringstream str;
+ str << "Block <" << current_chunk->name << "> already defined!";
+ state->push_error(errors::error{ errors::block_already_defined,str.str(),true,line });
+ return false;
+ }
+ }
+ current_chunk = new chunk;
+ current_chunk->name = bk_name;
+ chunk_type = bk_type;
+ current_chunk->type = bk_type;
+ print("Created Block: ",bk_name," <",bk_type,">");
+ return true;
+ }
+ void LineParser::tokenizer(dms_state* state,std::vector &toks) {
+ tokenstream stream;
+ stream.init(&toks);
+ this->state = state; // Grab the pointer to the state and store it within the parser object
+ _Parse(stream);
+ }
+ void LineParser::tolower(std::string &s1) {
+ std::transform(s1.begin(), s1.end(), s1.begin(), std::tolower);
+ }
+ LineParser::LineParser(std::string f) {
+ fn = f;
+ }
+ LineParser::LineParser() {}
+}
\ No newline at end of file
diff --git a/DMS/codes.cpp b/DMS/codes.cpp
index 40e25e1..2deedc1 100644
--- a/DMS/codes.cpp
+++ b/DMS/codes.cpp
@@ -1,3 +1,3 @@
#pragma once
#include "Codes.h"
-const std::string dms::codes::list[] = { "NOOP","ENTR","ENAB","DISA","LOAD","VERN","USIN","STAT","DISP","ASGN","LABL","CHOI","OPTN","FORE","????","WHLE","FNWR","FNNR","IFFF","ELIF","ELSE","DEFN","SKIP","COMP","INDX","JMPZ","INST","ERRO" ,"RETN" };
\ No newline at end of file
+const std::string dms::codes::list[] = { "NOOP","ENTR","ENAB","DISA","LOAD","VERN","USIN","STAT","DISP","ASGN","LABL","CHOI","OPTN","FORE","????","WHLE","FUNC","IFFF","ELIF","ELSE","DEFN","SKIP","COMP","INDX","JMPZ","INST","ERRO" ,"RETN" };
\ No newline at end of file
diff --git a/DMS/codes.h b/DMS/codes.h
index 26b340b..52dcf22 100644
--- a/DMS/codes.h
+++ b/DMS/codes.h
@@ -19,8 +19,7 @@ namespace dms::codes {
FORE,
UNWN,
WHLE,
- FNWR,
- FNNR,
+ FUNC,
IFFF,
ELIF,
ELSE,
diff --git a/DMS/dms_state.h b/DMS/dms_state.h
index 515c6af..8020619 100644
--- a/DMS/dms_state.h
+++ b/DMS/dms_state.h
@@ -3,6 +3,7 @@
#include "chunk.h"
#include
#include
+#include
namespace dms {
class dms_state
{
@@ -10,8 +11,8 @@ namespace dms {
void push_error(errors::error err);
void push_warning(errors::error err);
double version=1.0;
- std::map chunks;
+ std::unordered_map chunks;
std::string entry = "start";
- std::map enables;
+ std::unordered_map enables;
};
}
diff --git a/DMS/test.dms b/DMS/test.dms
index c541bc4..917b585 100644
--- a/DMS/test.dms
+++ b/DMS/test.dms
@@ -50,10 +50,10 @@ using extendedDefine
//Hello im testing stuff
CHOICE "Pick one:" {
- "first" func()
- "second" func()
- "third" func()
- "forth" func()
+ "first" func(1,2,3)
+ "second" func(true,false)
+ "third" func("hehe")
+ "forth" func("1",2,false)
"fifth" goto "here"
"sixth" goto name
"sevinth" jump "there"
diff --git a/DMS/token.h b/DMS/token.h
index ef6e6d9..42a168e 100644
--- a/DMS/token.h
+++ b/DMS/token.h
@@ -39,6 +39,7 @@ namespace dms::tokens {
ret,
gotoo,
jump,
+ exit,
nil
};//stream, t_vec, line, isNum, buffer
struct token {
@@ -97,6 +98,7 @@ namespace dms::tokens {
"ret",
"gotoo",
"jump",
+ "exit",
"nil"
};
out << "Line <" << c.line_num << ">" << codes::list[c.raw] << " " << temp1[c.type] << " \t\t " << c.name;
diff --git a/DMS/utils.cpp b/DMS/utils.cpp
index 60c8140..cf8f158 100644
--- a/DMS/utils.cpp
+++ b/DMS/utils.cpp
@@ -105,4 +105,7 @@ namespace dms::utils {
if (std::string::npos != p)
s.erase(p + 1);
}
+ void wait() {
+ std::cin.ignore();
+ }
}
\ No newline at end of file
diff --git a/DMS/utils.h b/DMS/utils.h
index ade6fb9..7eb3f3e 100644
--- a/DMS/utils.h
+++ b/DMS/utils.h
@@ -25,4 +25,5 @@ namespace dms::utils {
bool isalpha(std::string str);
bool isNum(std::string str);
void trim(std::string& s);
+ void wait();
}
\ No newline at end of file
diff --git a/DMS/value.cpp b/DMS/value.cpp
index 1995a34..81c616f 100644
--- a/DMS/value.cpp
+++ b/DMS/value.cpp
@@ -30,6 +30,15 @@ namespace dms {
temp << this;
return temp.str();
}
+ value* buildValue() {
+ return new value;
+ }
+ value* buildVariable(std::string str) {
+ value* val = new value{};
+ val->set(buildString(str));
+ val->type = variable;
+ return val;
+ }
value* buildValue(std::string str) {
value* val = new value{};
val->set(buildString(str));
diff --git a/DMS/value.h b/DMS/value.h
index 7922340..eb72bff 100644
--- a/DMS/value.h
+++ b/DMS/value.h
@@ -2,7 +2,7 @@
#include
#include
#include
-#include