commit d34ada27ee0885c8ee9a48580db62900192c417a Author: niansa Date: Mon Apr 13 14:36:26 2020 +0200 Initial commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ba077a4 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +bin diff --git a/examples/gettest.pil b/examples/gettest.pil new file mode 100644 index 0000000..0726c38 --- /dev/null +++ b/examples/gettest.pil @@ -0,0 +1,27 @@ +#This file is part of pilang. +# +#pilang is free software: you can redistribute it and/or modify +#it under the terms of the GNU General Public License as published by +#the Free Software Foundation, either version 3 of the License, or +#(at your option) any later version. +# +#pilang is distributed in the hope that it will be useful, +#but WITHOUT ANY WARRANTY; without even the implied warranty of +#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +#GNU General Public License for more details. +# +#You should have received a copy of the GNU General Public License +#along with pilang. If not, see . + +catch True +set userin,$input "Type in something: " + +set charnum,0 +marker set,printloop + sleep 0.1 + printnnl $get "$~userin,$~charnum" + inc charnum + cmp bigger,$len $~userin,$~charnum,"marker goto,printloop" + +print +marker goto,start diff --git a/examples/gettest2.pil b/examples/gettest2.pil new file mode 100644 index 0000000..7664b88 --- /dev/null +++ b/examples/gettest2.pil @@ -0,0 +1,35 @@ +#This file is part of pilang. +# +#pilang is free software: you can redistribute it and/or modify +#it under the terms of the GNU General Public License as published by +#the Free Software Foundation, either version 3 of the License, or +#(at your option) any later version. +# +#pilang is distributed in the hope that it will be useful, +#but WITHOUT ANY WARRANTY; without even the implied warranty of +#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +#GNU General Public License for more details. +# +#You should have received a copy of the GNU General Public License +#along with pilang. If not, see . + +catch True +# Store passed arguments as concenated string +set argslen,$argc +set counter,2 +set userin, +marker set,concatloop +# print $~counter, ,$argv $~counter + append userin,$argv $~counter," " + inc counter + cmp smaller,$~counter,$~argslen,"marker goto,concatloop" + +# Print character for character slowly +set charnum,0 +marker set,printloop + sleep 0.1 + printnnl $get "$~userin,$~charnum" + inc charnum + cmp bigger,$len $~userin,$~charnum,"marker goto,printloop" + +print diff --git a/examples/guessinggame.pil b/examples/guessinggame.pil new file mode 100644 index 0000000..d7de2b3 --- /dev/null +++ b/examples/guessinggame.pil @@ -0,0 +1,31 @@ +#This file is part of pilang. +# +#pilang is free software: you can redistribute it and/or modify +#it under the terms of the GNU General Public License as published by +#the Free Software Foundation, either version 3 of the License, or +#(at your option) any later version. +# +#pilang is distributed in the hope that it will be useful, +#but WITHOUT ANY WARRANTY; without even the implied warranty of +#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +#GNU General Public License for more details. +# +#You should have received a copy of the GNU General Public License +#along with pilang. If not, see . + +catch true +set number,4 + +print "Guess the first number..." +marker set,mainloop + set guess,$input "Guess a number: " + cmp equal,$~guess,,"marker goto,mainloop" + cmp isnotnum,$~guess,0,"print That's not a number. Retry with a number!","marker goto,mainloop" + cmp bigger,$~guess,$~number,"print Retry with a lower number!","marker goto,mainloop" + cmp smaller,$~guess,$~number,"print Retry with a higher number!","marker goto,mainloop" + +print "You guessed it! It's ",$~number,! +print "Now guess another number..." + +inc number,7 +marker goto,mainloop diff --git a/examples/simple.pil b/examples/simple.pil new file mode 100644 index 0000000..78eadef --- /dev/null +++ b/examples/simple.pil @@ -0,0 +1,31 @@ +#This file is part of pilang. +# +#pilang is free software: you can redistribute it and/or modify +#it under the terms of the GNU General Public License as published by +#the Free Software Foundation, either version 3 of the License, or +#(at your option) any later version. +# +#pilang is distributed in the hope that it will be useful, +#but WITHOUT ANY WARRANTY; without even the implied warranty of +#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +#GNU General Public License for more details. +# +#You should have received a copy of the GNU General Public License +#along with pilang. If not, see . + +# Enable error catching +catch True +# Initialise stuff +set wasword,was +# Get input from user +set errnonum,Whatever you typed in... It's definitely not a number!!! +set name,$input "Name: " +cmp equal,$~name,,"print What? That person has no name???",exit 1 +set birth year,$input "Year of birth: " +cmp isnotnum,$~birth year,0,print $~errnonum,exit 3 +set current year,$input "Current year: " +cmp isnotnum,$~current year,0,print $~errnonum,exit 3 +# Check if birth year is before current year +cmp smaller,$~current year,$~birth year,"print Will ,$~name, be born in the future?","set yesno,$input Yes/No?: ","cmp equal,$lower $~yesno,no,exit 4","cmp nonequal,$lower $~yesno,yes,print I give you up... Bye!,exit 4","set wasword,will be" +# Print result +print $~name, ,$~wasword, born in ,$~birth year, and we are in ,$~current year,",", so I guess ,$~name, is ,$"sub asint,$~current year,$~birth year", years old! diff --git a/main.cpp b/main.cpp new file mode 100644 index 0000000..bc59149 --- /dev/null +++ b/main.cpp @@ -0,0 +1,566 @@ +/* +This file is part of pilang. + +pilang is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +pilang is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with pilang. If not, see . +*/ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + + +// Return type defs +std::string success = "Success"; +std::string failed = "Failed"; +std::string nosuchcommand = "No such command"; +std::string nosuchvariable = "No such variable"; +std::string badarguments = "Bad arguments"; + +// Exception defs +class markergoto : public std::string {}; +std::string markergotoname; + +// Environment defs +std::vector cmdargs; +std::map variables; +std::map markers; +bool interactivecli; +std::vector markersetqueue; +std::string execline(std::string commandstr); + +// Helper functions +bool is_float(std::string s) { + std::istringstream iss(s); + float f; + iss >> std::noskipws >> f; + return iss.eof() && !iss.fail(); +} +std::string str_lower(std::string string) { + std::transform(string.begin(), string.end(), string.begin(), ::tolower); + return string; +} +std::string str_upper(std::string string) { + std::transform(string.begin(), string.end(), string.begin(), ::toupper); + return string; +} +std::string ltrim(const std::string& s) { + static const std::regex lws{"^[[:space:]]*", std::regex_constants::extended}; + return std::regex_replace(s, lws, ""); +} +std::string rtrim(const std::string& s) { + static const std::regex tws{"[[:space:]]*$", std::regex_constants::extended}; + return std::regex_replace(s, tws, ""); +} +std::string trim(const std::string& s) { + return ltrim(rtrim(s)); +} +std::vector strsplit(std::string_view s, char delimiter, std::vector::size_type times = 0) { + std::vector to_return; + decltype(s.size()) start = 0, finish = 0; + while ((finish = s.find_first_of(delimiter, start)) != std::string_view::npos) { + to_return.emplace_back(s.substr(start, finish - start)); + start = finish + 1; + if (to_return.size() == times) { break; } + } + to_return.emplace_back(s.substr(start)); + return to_return; +} +void do_markersetqueue(int currline) { + for (const std::string & markername : markersetqueue) { + markers[markername] = currline; + } + markersetqueue = {}; +} + +// Builtin functions +std::string cmd_ret(std::vector args) { + std::string retstring; + for (const std::string & arg : args){ + retstring.append(arg); + } + return retstring; +} +std::string cmd_get(std::vector args) { + if (args.size() != 2) { + return badarguments; + } + auto argsit = args.begin(); + std::string string = *argsit; + argsit++; + long unsigned int position = std::stoi(*argsit); + if (position < string.length()) { + std::string res; + res.push_back(string.at(position)); + return res; + } else { + return badarguments; + } +} +std::string cmd_len(std::vector args) { + int result = 0; + for (const std::string & arg : args){ + result += arg.length(); + } + return std::to_string(result); +} +std::string cmd_exit(std::vector args) { + //Check amount of arguments + if (args.size() != 1) { + return badarguments; + } + std::string exitcode = *args.begin(); + if (is_float(exitcode)) + exit(std::stoi(exitcode)); + else + return badarguments; +} +std::string cmd_marker(std::vector args) { + // Check amount of arguments + if (args.size() != 2) { + return badarguments; + } + // Get arguments + auto argsit = args.begin(); + std::string action = *argsit; + argsit++; + std::string markername = *argsit; + // Set or goto + if (action == "goto") { + markergotoname = markername; + throw markergoto(); + } else if (action == "set") { + markersetqueue.push_back(markername); + } else { + return badarguments; + } + return success; +} +std::string cmd_printnnl(std::vector args) { + std::cout << cmd_ret(args) << std::flush; + return success; +} +std::string cmd_print(std::vector args) { + auto result = cmd_printnnl(args); + std::cout << std::endl; + return result; +} +std::string cmd_input(std::vector args) { + cmd_printnnl(args); + std::string result; + std::getline(std::cin, result); + return result; +} +std::string cmd_set(std::vector args) { + //Check amount of arguments + if (args.size() != 2) { + return badarguments; + } + // Get arguments + auto argsit = args.begin(); + std::string key = *argsit; + argsit++; + std::string value = *argsit; + // Store in environment + variables[key] = value; + // Return success + return success; +} +std::string cmd_append(std::vector args) { + //Check amount of arguments + if (args.size() < 2) { + return badarguments; + } + // Get arguments + auto argsit = args.begin(); + std::string variablename = *argsit; + argsit++; + for (int dummy; argsit != args.end(); argsit++) + variables[variablename].append(*argsit); + return success; +} +std::string cmd_incdec(bool type, std::vector args) { + //Check amount of arguments + if (args.size() < 1 or args.size() > 2) { + return badarguments; + } + // Get arguments + auto argsit = args.begin(); + std::string variablename = *argsit; + float incby; + if (args.size() == 2) { + argsit++; + incby = std::atof((*argsit).c_str()); + } else { + incby = 1; + } + // Modify variable if it exists + if (variables.find(variablename) == variables.end()) { + return nosuchvariable; + } else { + float currval = std::atof(variables[variablename].c_str()); + if (type) + currval += incby; + else + currval -= incby; + variables[variablename] = std::to_string(currval); + } + return success; +} +std::string cmd_del(std::vector args) { + if (args.size() < 1) { + return badarguments; + } + for (const std::string & arg : args) { + auto varit = variables.find(arg); + if (varit != variables.end()) { + variables.erase(variables.find(arg)); + } + } + return success; +} +std::string cmd_eval(std::vector args) { + if (args.size() < 1) { + return badarguments; + } + std::string result; + for (const std::string & arg : args) { + result = execline(arg); + } + return result; +} +std::string cmd_cmp(std::vector args) { + bool matches; + //Check amount of arguments + if (args.size() < 4) { + return badarguments; + } + // Get arguments + auto argsit = args.begin(); + std::string action = *argsit; + argsit++; + std::string var1 = *argsit; + argsit++; + std::string var2 = *argsit; + argsit++; + // Compare + if (action == "equal") + matches = var1 == var2; + else if (action == "nonequal") + matches = var1 != var2; + else if (action == "bigger") + matches = std::atof(var1.c_str()) > std::atof(var2.c_str()); + else if (action == "smaller") + matches = std::atof(var1.c_str()) < std::atof(var2.c_str()); + else if (action == "isnum" or action == "isnotnum") { + matches = is_float(var1) and is_float(var2); + if (action == "isnotnum") + matches = !matches; + } else + return badarguments; + // Eval on match + if (matches) { + std::string result; + while (argsit != args.end()) { + result = execline(*argsit); + argsit++; + } + return result; + } else { + return failed; + } +} +std::string cmd_lowerupper(bool type, std::vector args) { + if (args.size() < 1) { + return badarguments; + } + std::string result; + for (auto argsit = args.begin(); argsit != args.end(); argsit++) { + if (type) + result.append(str_upper(*argsit)); + else + result.append(str_lower(*argsit)); + } + return result; +} +std::string cmd_addsub(bool type, std::vector args) { + //Check amount of arguments + if (args.size() < 2) { + return badarguments; + } + // Initialise variables + bool asint = false; + float numarg; + // Get arguments + auto argsit = args.begin(); + if (*argsit == "asint") { + asint = true; + argsit++; + } + // Initialise initial result + if (!is_float(*argsit)) + return badarguments; + float result = std::atof((*argsit).c_str()); + argsit++; + // Calculaté + for (int dummy; argsit != args.end(); argsit++) { + if (!is_float(*argsit)) + return badarguments; + numarg = std::atof((*argsit).c_str()); + if (type) + result += numarg; + else + result -= numarg; + } + // Return result + if (asint) + return std::to_string((int) result); + else + return std::to_string(result); +} +std::string cmd_sleep(std::vector args) { + // Check amount of arguments + if (args.size() != 1) { + return badarguments; + } + // Check argument + auto argsit = args.begin(); + if (!is_float(*argsit)) + return badarguments; + // Get argument + float sleepnsecs = std::atof((*argsit).c_str()) * 1000000; + usleep(sleepnsecs); + return success; +} +std::string cmd_argv(std::vector args) { + // Check amount of arguments + if (args.size() != 1) { + return badarguments; + } + // Check argument + auto argsit = args.begin(); + if (!is_float(*argsit)) + return badarguments; + long unsigned int argnum = std::atoi((*argsit).c_str()); + if (argnum >= cmdargs.size()) + return badarguments; + // Get argument + return cmdargs[argnum]; +} +std::string cmd_argc(std::vector args) { + return std::to_string(cmdargs.size()); +} + +std::string run_command(std::string command, std::vector args) { + //std::cout << "Running command:" << command << "!" << std::endl; + if (command == "ret") + return cmd_ret(args); + else if (command == "get") + return cmd_get(args); + else if (command == "len") + return cmd_len(args); + else if (command == "exit") + return cmd_exit(args); + else if (command == "marker") + return cmd_marker(args); + else if (command == "print") + return cmd_print(args); + else if (command == "printnnl") + return cmd_printnnl(args); + else if (command == "input") + return cmd_input(args); + else if (command == "set") + return cmd_set(args); + else if (command == "append") + return cmd_append(args); + else if (command == "inc") + return cmd_incdec(true, args); + else if (command == "dec") + return cmd_incdec(false, args); + else if (command == "del") + return cmd_del(args); + else if (command == "eval") + return cmd_eval(args); + else if (command == "cmp") + return cmd_cmp(args); + else if (command == "lower") + return cmd_lowerupper(false, args); + else if (command == "upper") + return cmd_lowerupper(true, args); + else if (command == "add") + return cmd_addsub(true, args); + else if (command == "sub") + return cmd_addsub(false, args); + else if (command == "sleep") + return cmd_sleep(args); + else if (command == "argv") + return cmd_argv(args); + else if (command == "argc") + return cmd_argc(args); + else + return "No such command"; +} + +// Interpreter initialiser +void init_interpreter(int argc, char *argv[]) { + // Load modules from modules directory + struct dirent *dp; + DIR *dfd; + char filename_qfd[264]; + char moduledir [] = "modules"; + dfd = opendir(moduledir); + while ((dp = readdir(dfd)) != NULL) { + sprintf(filename_qfd , "%s/%s",moduledir,dp->d_name); + // Skip . and .. + if (strcmp(dp->d_name,"..") or strcmp(dp->d_name,".")) + continue; + // Load file + std::cout << "Module loading not yet implemented for: " << filename_qfd << std::endl; + } + // Generate list of arguments + for (int elemnum = 0; elemnum < argc; elemnum++) { + cmdargs.push_back(std::string(argv[elemnum])); + } +} + +std::string execline(std::string commandstr) { + commandstr = ltrim(commandstr.substr(0, commandstr.find("#", 0))); + //std::cout << "$ " << commandstr << std::endl; + if (rtrim(commandstr) == "") { // Command is empty + return commandstr; + } else if (commandstr.rfind('~', 0) == 0) { // Command is a variable + commandstr.erase(0, 1); + // Check if variable exists + if (variables.find(commandstr) == variables.end()) { + return nosuchvariable; + } else { + return variables[commandstr]; + } + } else { // Command is an actual command + std::vector cmdsplit = strsplit(commandstr, ' ', 1); + auto cmdsplit_it = cmdsplit.begin(); + std::string command = *cmdsplit_it; + std::string argsstr = ""; + cmdsplit_it++; + if (cmdsplit.size() == 2) { + argsstr = *cmdsplit_it; + argsstr.push_back(','); + } + std::vector args; + if (argsstr != ",") { + std::string currarg = ""; + bool instring = false; + bool arginstring = false; + bool charig = false; + bool skipall = false; + for (std::string::iterator currchar = argsstr.begin(); currchar < argsstr.end(); currchar++) { + if (skipall) { + continue; + } else if (*currchar == '"' and !skipall) { + instring = !instring; + if (currarg == "") + arginstring = true; + } else if (*currchar == '#' and !charig and !instring) { + skipall = true; + } else if (*currchar == ',' and !charig and !instring) { + if (currarg.length() != 0 and *currarg.begin() == '$' and !arginstring) { + currarg.erase(0, 1); + currarg = execline(currarg); + } + args.push_back(currarg); + currarg = ""; + arginstring = false; + } else if (*currchar == '\\' and !charig) { + charig = true; + } else { + currarg.push_back(*currchar); + charig = false; + } + } + } + //std::cout << "Args len: " << args.size() << std::endl; + return run_command(command, args); + } +} + + + + +// Main CLI +int main(int argc, char *argv[]) { + std::string line; + using namespace std; + if (argc == 1) { // Start interactive CLI + // Show copyright note + cout << "pilang Copyright (C) 2020 niansa" << endl; + cout << "This program comes with ABSOLUTELY NO WARRANTY; for details type `warranty'." << endl; + cout << "This is free software, and you are welcome to redistribute it" << endl; + cout << "under certain conditions; type `license' for details." << endl; + cout << endl; + // Initialise stuff + init_interpreter(argc, argv); + interactivecli = true; + // Input loop + while (true) { + line = ""; + cout << ">>> " << flush; + std::getline(std::cin, line); + cout << execline(line) << endl; + } + } else { + // Read from argv[1] into vector + std::ifstream scriptfile(argv[1]); + std::vector lines; + std::string line; + while (std::getline(scriptfile, line)) { + lines.push_back(line); + if (scriptfile.eof()) { break; } // EOF + } + scriptfile.close(); + // Initialise stuff + init_interpreter(argc, argv); + interactivecli = false; + // Add initial marker in line 0 + markersetqueue.push_back("start"); + do_markersetqueue(0); + // Execute vector line-by-line + auto linesit = lines.begin(); + for (int currline = 0; linesit != lines.end(); currline++) { + try { + execline(*linesit); + do_markersetqueue(currline); // Do markerqueue + } catch (markergoto) { // Catch marker goto + do_markersetqueue(currline); // Do markerqueue even if an exception occured + if (markers.find(markergotoname) != markers.end()) { + currline = markers[markergotoname]; + linesit = lines.begin() + currline; + } else { + cerr << "No such marker: \"" << markergotoname << "\" (critical)" << endl; + return 77; + } + } + linesit++; + } + } +} diff --git a/obj/Debug/main.o b/obj/Debug/main.o new file mode 100644 index 0000000..39bf242 Binary files /dev/null and b/obj/Debug/main.o differ diff --git a/obj/Debug/src/environment.o b/obj/Debug/src/environment.o new file mode 100644 index 0000000..e3f3523 Binary files /dev/null and b/obj/Debug/src/environment.o differ diff --git a/obj/Debug/src/interpreter.o b/obj/Debug/src/interpreter.o new file mode 100644 index 0000000..b7df26a Binary files /dev/null and b/obj/Debug/src/interpreter.o differ diff --git a/obj/Debug/src/module_builtin.o b/obj/Debug/src/module_builtin.o new file mode 100644 index 0000000..e798e2e Binary files /dev/null and b/obj/Debug/src/module_builtin.o differ diff --git a/obj/Debug/src/rtypes.o b/obj/Debug/src/rtypes.o new file mode 100644 index 0000000..afadcf6 Binary files /dev/null and b/obj/Debug/src/rtypes.o differ diff --git a/pilang.cbp b/pilang.cbp new file mode 100644 index 0000000..87327a4 --- /dev/null +++ b/pilang.cbp @@ -0,0 +1,43 @@ + + + + + + diff --git a/pilang.depend b/pilang.depend new file mode 100644 index 0000000..a507ed5 --- /dev/null +++ b/pilang.depend @@ -0,0 +1,57 @@ +# depslib dependency file v1.0 +1586773944 source:/home/nils/Programme/OSS/codeblocks/pilang/main.cpp + + + + + + + + + + + + + +1586692463 /home/nils/Programme/OSS/codeblocks/pilang/include/interpreter.h + + + + + +1586614898 source:/home/nils/Programme/OSS/codeblocks/pilang/src/environment.cpp + "environment.h" + +1586614630 /home/nils/Programme/OSS/codeblocks/pilang/include/environment.h + + +1586691513 source:/home/nils/Programme/OSS/codeblocks/pilang/src/interpreter.cpp + + + + + + + + + + +1586690920 source:/home/nils/Programme/OSS/codeblocks/pilang/src/module_builtin.cpp + "module_builtin.h" + + + + +1586690835 /home/nils/Programme/OSS/codeblocks/pilang/include/module_builtin.h + + + + + +1586690671 /home/nils/Programme/OSS/codeblocks/pilang/include/rtypes.h + + + +1586687677 source:/home/nils/Programme/OSS/codeblocks/pilang/src/rtypes.cpp + "rtypes.h" + diff --git a/pilang.layout b/pilang.layout new file mode 100644 index 0000000..2d11302 --- /dev/null +++ b/pilang.layout @@ -0,0 +1,10 @@ + + + + + + + + + +