diff --git a/Bobfile b/Bobfile index c50ee3c..89aa177 100644 --- a/Bobfile +++ b/Bobfile @@ -1,5 +1,4 @@ compiler "g++"; binary "ground"; source "src/main.cpp"; -flag "O3"; compile; diff --git a/docs/syntax.md b/docs/syntax.md index bf03271..8972dc1 100644 --- a/docs/syntax.md +++ b/docs/syntax.md @@ -32,6 +32,18 @@ Reference a line (a line reference) with a percent symbol before a line number: jump %10 ``` +(WORK IN PROGRESS) Alternatively, set a label and jump to that (setting labels will be discussed below): + +``` + jump %myLabel +``` + +Reference a list (a list reference) with an asterisk: + +``` + setlist *myList $value1 $value2 # and so on +``` + ### Keywords Note: &var can be replaced with any direct reference. $value can be replaced with a literal value or a value reference. %1 can be replaced with a line reference. @@ -54,7 +66,7 @@ Usage: `jump %1` Ends the program. Requires an integer for a status code. -Usage: `end $value` +Usage: `end $intvalue` #### stdin @@ -80,6 +92,30 @@ Allows you to set a variable to a value. Usage: `set &var $value` +#### setlist + +Allows you to initialize a list. + +Usage: `setlist *list $value1 $value2 $value3...` + +#### setlistat (WORK IN PROGRESS) + +Sets a list item at an index. The item at the index must already exist. Lists are index 0. + +Usage: `setlistat *list $intvalue $value` + +#### getlistat + +Gets a list item at an index, and puts it in the variable provided. The item at the index must already exist. Lists are index 0. + +Usage: `getlistat *list $intvalue &var` + +#### getlistsize + +Gets the size of a list and puts it in the variable provided. + +Usage: `getlistsize *list &var` + #### add Adds two numbers. Numbers mean an integer or a double. Outputs to a direct reference. @@ -126,4 +162,4 @@ Usage: `greater $value $value &var` Checks if the left value is lesser than the right value. Outputs a boolean to a direct reference. -Usage: `lesser $value $value &var` \ No newline at end of file +Usage: `lesser $value $value &var` diff --git a/src/main.cpp b/src/main.cpp index 794dace..eb47931 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -49,7 +49,12 @@ using namespace std; function, interpreter function, Instruction struct */ enum class Instructions { - Jump, Stdout, Stdin, Stdlnout, Add, Subtract, Multiply, Divide, Equal, Inequal, Greater, Lesser, If, End, Set, Empty + Jump, If, + Stdout, Stdin, Stdlnout, + Add, Subtract, Multiply, Divide, + Equal, Inequal, Greater, Lesser, + End, Set, Empty, + Setlist, Getlistat, Setlistat, Getlistsize }; /* @@ -67,7 +72,7 @@ enum class Instructions { See also parser function */ enum class Types { - Int, Double, String, Char, Bool, Value, Direct, Line + Int, Double, String, Char, Bool, Value, Direct, Line, ListRef }; /* @@ -86,12 +91,61 @@ struct Literal { variant val; }; +/* + List struct + Contains literal values inside a vector. For example, if the following + program was written: + setlist #myNums 3 5 9 13 + The List struct which would be created and stored should look like this: + { + val = { + Literal { + val = 3 + }, + Literal { + val = 5 + }, + Literal { + val = 9 + }, + Literal { + val = 13 + }, + } + } + All elements in the list must be of the same type. See also Literal struct. +*/ +struct List { + vector val; +}; + +/* + ListRef struct + Contains the name of a list referenced by the program. For example, if the + following program was written: + setlist #myNums 3 5 9 13 + The ListRef struct should look like this: + { + listName = "myNums"; + } +*/ +struct ListRef { + string listName; +}; + /* variables map Contains all variables made while running the program. See also Literal struct. */ map variables; + +/* + lists map + Contains all lists made while running the program. See also List struct. +*/ +map lists; + /* ValueRef struct If the program being executed makes a value reference, it is stored in a ValueRef @@ -161,7 +215,7 @@ struct Line { */ struct Instruction { Instructions inst = Instructions::Empty; - vector> args; + vector> args; }; /* @@ -224,7 +278,12 @@ bool isDirect(string in) { } bool isLine(string in) { - if (in.size() >= 1 && in[0] == '%' && isInt(in.substr(1))) return true; + if (in.size() >= 1 && in[0] == '%') return true; + else return false; +} + +bool isListRef(string in) { + if (in.size() >= 1 && in[0] == '*') return true; else return false; } @@ -242,6 +301,7 @@ Types getType(string in) { if (isValue(in)) return Types::Value; if (isDirect(in)) return Types::Direct; if (isLine(in)) return Types::Line; + if (isListRef(in)) return Types::ListRef; error("Could not determine type of \"" + in + "\""); return Types::Int; } @@ -368,6 +428,114 @@ void exec(vector in) { variables[varName] = varContents; } break; + /* + setlist instruction + This instruction takes a potentially infinite amount of arguments and + saves them to a list (vector) with name listName. + */ + case Instructions::Setlist: + if (l.args.size() < 2) { + error("Could not find all arguments required for Setlist inbuilt"); + } + { + string listName; + List listContents; + + if (holds_alternative(l.args[0])) { + listName = get(l.args[0]).listName; + } else { + error("First argument of setlist must be a list reference"); + } + + bool first = true; + for (variant k : l.args) { + if (holds_alternative(k)) { + listContents.val.push_back(get(k)); + } else { + if (!first) error("All arguments after first in setlist must be values"); + first = false; + } + } + lists[listName] = listContents; + } + break; + /* + getlistat instruction + This instruction gets a list item from a list and an index and saves the + value to a variable. + */ + case Instructions::Getlistat: + if (l.args.size() < 3) { + error("Could not find all arguments required for Getlistat inbuilt"); + } + { + ListRef listref; + int ref; + Direct var; + + if (holds_alternative(l.args[0])) { + listref = get(l.args[0]); + } else { + error("First argument of getlistat must be a list reference"); + } + + if (holds_alternative(l.args[1])) { + if (holds_alternative(get(l.args[1]).val)) { + ref = get(get(l.args[1]).val); + } else { + error("Second argument of getlistat must be an integer literal"); + } + } else { + error("Second argument of getlistat must be an integer literal"); + } + + if (holds_alternative(l.args[2])) { + var = get(l.args[2]); + } else { + error("Third argument of getlistat must be a direct reference"); + } + + if (lists.find(listref.listName) != lists.end()) { + if (lists[listref.listName].val.size() > ref) { + variables[var.varName] = lists[listref.listName].val[ref]; + } else { + error("Index " + to_string(ref) + " out of range of list " + listref.listName); + } + } else { + error("Unknown list: " + listref.listName); + } + } + break; + case Instructions::Getlistsize: + if (l.args.size() < 2) { + error("Could not find all arguments required for Getlistsize inbuilt"); + } + { + ListRef ref; + Direct var; + + if (holds_alternative(l.args[0])) { + ref = get(l.args[0]); + } else { + error("First argument of getlistsize must be a list reference"); + } + + if (holds_alternative(l.args[1])) { + var = get(l.args[1]); + } else { + error("Second argument of getlistsize must be a direct reference"); + } + + Literal newLit; + if (lists.find(ref.listName) != lists.end()) { + newLit.val = int(lists[ref.listName].val.size()); + variables[var.varName] = newLit; + } else { + error("Couldn't find the list " + ref.listName); + } + + break; + } /* stdin instruction This instruction takes input from the standard character input via @@ -375,7 +543,7 @@ void exec(vector in) { */ case Instructions::Stdin: if (l.args.size() < 1) { - error("Could not find all arguments require for Stdin inbuilt"); + error("Could not find all arguments required for Stdin inbuilt"); } if (holds_alternative(l.args[0])) { string userIn; @@ -980,6 +1148,10 @@ vector parser(vector> in) { else if (i == "inequal") newInst.inst = Instructions::Inequal; else if (i == "end") newInst.inst = Instructions::End; else if (i == "set") newInst.inst = Instructions::Set; + else if (i == "setlist") newInst.inst = Instructions::Setlist; + else if (i == "setlistat") newInst.inst = Instructions::Setlistat; + else if (i == "getlistat") newInst.inst = Instructions::Getlistat; + else if (i == "getlistsize") newInst.inst = Instructions::Getlistsize; else error("Unexpected token: " + i); } else { Types type = getType(i); @@ -1005,6 +1177,13 @@ vector parser(vector> in) { newInst.args.push_back(newLine); } break; + case Types::ListRef: + { + ListRef newLR; + newLR.listName = i.substr(1); + newInst.args.push_back(newLR); + } + break; case Types::String: { Literal newLiteral; diff --git a/tests/lists.grnd b/tests/lists.grnd new file mode 100644 index 0000000..ffa89c6 --- /dev/null +++ b/tests/lists.grnd @@ -0,0 +1,9 @@ +setlist *favNums "hello" "there" "general" "kenobi" +set &count 0 +getlistat *favNums $count &tmp +stdlnout $tmp +add $count 1 &count +getlistsize *favNums &tmp2 +inequal $count $tmp2 &tmp3 +if $tmp3 %3 +stdlnout "finished!"