├── .gitignore ├── CMakeLists.txt ├── LICENSE ├── README.md ├── compiler ├── main.py └── passes.py ├── docs ├── logo.png ├── ops.md └── ops_cheatsheet.md ├── impl ├── make_ops.h ├── ops.h └── ops │ ├── bitshift.h │ ├── comparison.h │ ├── functions.h │ ├── group_comparison.h │ ├── group_math.h │ ├── io.h │ ├── jump.h │ ├── logical.h │ ├── math.h │ ├── other.h │ ├── rel_jump.h │ └── stack_manipulation.h ├── main.cpp ├── scripts ├── counter.wot ├── functions.wot ├── helloworld.wb ├── helloworld.wot ├── math.wot ├── string.wot └── test.wot └── wotpp ├── core.h ├── object ├── object.cpp └── object.h ├── stack ├── stack.cpp └── stack.h ├── stack_group ├── stack_group.cpp └── stack_group.h ├── utils.h ├── utils ├── read_file.h └── types.h └── vm ├── vm.cpp └── vm.h /.gitignore: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | *.d 3 | 4 | # Compiled Object files 5 | *.slo 6 | *.lo 7 | *.o 8 | *.obj 9 | 10 | # Precompiled Headers 11 | *.gch 12 | *.pch 13 | 14 | # Compiled Dynamic libraries 15 | *.so 16 | *.dylib 17 | *.dll 18 | 19 | # Fortran module files 20 | *.mod 21 | *.smod 22 | 23 | # Compiled Static libraries 24 | *.lai 25 | *.la 26 | *.a 27 | *.lib 28 | 29 | # Executables 30 | *.exe 31 | *.out 32 | *.app 33 | 34 | LICENSE 35 | vm/build 36 | 37 | # Byte-compiled / optimized / DLL files 38 | __pycache__/ 39 | *.py[cod] 40 | *$py.class 41 | 42 | # C extensions 43 | *.so 44 | 45 | # Distribution / packaging 46 | .Python 47 | build/ 48 | develop-eggs/ 49 | dist/ 50 | downloads/ 51 | eggs/ 52 | .eggs/ 53 | lib/ 54 | lib64/ 55 | parts/ 56 | sdist/ 57 | var/ 58 | wheels/ 59 | *.egg-info/ 60 | .installed.cfg 61 | *.egg 62 | MANIFEST 63 | 64 | # PyInstaller 65 | # Usually these files are written by a python script from a template 66 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 67 | *.manifest 68 | *.spec 69 | 70 | # Installer logs 71 | pip-log.txt 72 | pip-delete-this-directory.txt 73 | 74 | # Unit test / coverage reports 75 | htmlcov/ 76 | .tox/ 77 | .coverage 78 | .coverage.* 79 | .cache 80 | nosetests.xml 81 | coverage.xml 82 | *.cover 83 | .hypothesis/ 84 | 85 | # Translations 86 | *.mo 87 | *.pot 88 | 89 | # Django stuff: 90 | *.log 91 | .static_storage/ 92 | .media/ 93 | local_settings.py 94 | 95 | # Flask stuff: 96 | instance/ 97 | .webassets-cache 98 | 99 | # Scrapy stuff: 100 | .scrapy 101 | 102 | # Sphinx documentation 103 | docs/_build/ 104 | 105 | # PyBuilder 106 | target/ 107 | 108 | # Jupyter Notebook 109 | .ipynb_checkpoints 110 | 111 | # pyenv 112 | .python-version 113 | 114 | # celery beat schedule file 115 | celerybeat-schedule 116 | 117 | # SageMath parsed files 118 | *.sage.py 119 | 120 | # Environments 121 | .env 122 | .venv 123 | env/ 124 | venv/ 125 | ENV/ 126 | env.bak/ 127 | venv.bak/ 128 | 129 | # Spyder project settings 130 | .spyderproject 131 | .spyproject 132 | 133 | # Rope project settings 134 | .ropeproject 135 | 136 | # mkdocs documentation 137 | /site 138 | 139 | # mypy 140 | .mypy_cache/ 141 | 142 | # Directories 143 | bin/ 144 | compiler/__pycache__ 145 | 146 | # Wot++ bytecode 147 | *.wb -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 2.8) 2 | set(PROJECT_NAME vm) 3 | project(${PROJECT_NAME}) 4 | 5 | 6 | # SOURCE FILES 7 | set(MAIN main.cpp) 8 | 9 | 10 | file(GLOB_RECURSE OBJECT 11 | "wotpp/object/*.cpp" 12 | ) 13 | 14 | 15 | file(GLOB_RECURSE STACK 16 | "wotpp/stack/*.cpp" 17 | ) 18 | 19 | 20 | file(GLOB_RECURSE VM 21 | "wotpp/vm/*.cpp" 22 | ) 23 | 24 | 25 | file(GLOB_RECURSE STACKGROUP 26 | "wotpp/stack_group/*.cpp" 27 | ) 28 | 29 | 30 | file(GLOB_RECURSE OPS 31 | "wotpp/ops/*.cpp" 32 | ) 33 | 34 | 35 | # EXECUTABLE 36 | add_executable(${PROJECT_NAME} ${OBJECT} ${VM} ${STACK} ${STACKGROUP} ${OPS} ${MAIN}) 37 | 38 | 39 | # FILTERS 40 | source_group("object" FILES ${OBJECT}) 41 | source_group("stack" FILES ${STACK}) 42 | source_group("vm" FILES ${VM}) 43 | source_group("stack_group" FILES ${STACKGROUP}) 44 | source_group("ops" FILES ${OPS}) 45 | 46 | 47 | # LINK 48 | #target_link_libraries(${PROJECT_NAME}) 49 | 50 | 51 | # GCC 52 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Werror -Wno-unused-parameter -Wextra -Ofast -flto -m64") 53 | 54 | 55 | # PROPERTIES 56 | set_target_properties(${PROJECT_NAME} PROPERTIES 57 | CXX_STANDARD 14 58 | CXX_STANDARD_REQUIRED ON 59 | CXX_EXTENSIONS OFF 60 | ) 61 | 62 | 63 | # FILE DEPENDENCIES 64 | # Copies scripts folder into build directory. 65 | add_custom_command( 66 | TARGET ${PROJECT_NAME} POST_BUILD 67 | COMMAND ${CMAKE_COMMAND} -E copy_directory 68 | ${CMAKE_SOURCE_DIR}/scripts $/scripts 69 | ) -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Jack Clarke 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | 3 |

4 | 5 | # Wot++ 6 | 7 | The best damn language to ever grace the face of the Earth. 8 | 9 | [Specification](./docs/ops.md) 10 | 11 | [Cheatsheet](./docs/ops_cheatsheet.md) 12 | 13 | 14 | -------------------------------------------------------------------------------- /compiler/main.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | import os 3 | import sys 4 | 5 | import passes 6 | 7 | 8 | OPCODE_DICT = { 9 | "PSHL" : 0, 10 | "PUSH" : 1, 11 | "STOR" : 2, 12 | "POP" : 3, 13 | 14 | "PRNT" : 4, 15 | "EMIT" : 5, 16 | "PRNL" : 6, 17 | "EMTL" : 7, 18 | 19 | "SUM" : 8, 20 | "PROD" : 9, 21 | 22 | "ADD" : 10, 23 | "SUB" : 11, 24 | "MUL" : 12, 25 | "DIV" : 13, 26 | "MOD" : 14, 27 | "NEG" : 15, 28 | "INCR" : 16, 29 | "DECR" : 17, 30 | 31 | "LSHF" : 18, 32 | "RSHF" : 19, 33 | "LROT" : 20, 34 | "RROT" : 21, 35 | 36 | "AND" : 22, 37 | "OR" : 23, 38 | "XOR" : 24, 39 | "NOT" : 25, 40 | 41 | "ALL" : 26, 42 | "ANY" : 27, 43 | 44 | "CMEQ" : 28, 45 | "CMNL" : 29, 46 | "CMLT" : 30, 47 | "CMMT" : 31, 48 | 49 | "JUMP" : 32, 50 | "JPEQ" : 33, 51 | "JPNL" : 34, 52 | 53 | "JMPR" : 35, 54 | "JREQ" : 36, 55 | "JRNL" : 37, 56 | 57 | "CALL" : 38, 58 | "RET" : 39, 59 | 60 | "HALT" : 40, 61 | "NOOP" : 41 62 | } 63 | 64 | 65 | DIR_DICT = { 66 | "LABEL" : 0, 67 | "INCLUDE" : 1 68 | } 69 | 70 | 71 | TOKEN = { 72 | "type" : None, 73 | "body" : { 74 | "name" : None, 75 | "args" : [] 76 | } 77 | } 78 | 79 | 80 | PERSIST = { 81 | "opcodes" : OPCODE_DICT, 82 | "directives" : DIR_DICT, 83 | 84 | "labels" : {}, 85 | 86 | "token_type" : TOKEN, 87 | 88 | "op_typename" : "OPERATION", 89 | "dir_typename" : "DIRECTIVE", 90 | 91 | "number_typename" : "NUMBER", 92 | "string_typename" : "STRING", 93 | "char_typename" : "CHAR", 94 | "label_typename" : "LABEL" 95 | } 96 | 97 | 98 | FUNCTIONS = [ 99 | passes.strip_comments, 100 | passes.format_statements, 101 | passes.format_arguments, 102 | passes.fill_empty_arguments, 103 | 104 | passes.tokenise_statements, 105 | passes.match_token_ids, 106 | passes.tokenise_args, 107 | 108 | passes.parse_strings, 109 | passes.parse_chars, 110 | passes.encode_chars, 111 | 112 | passes.find_label_positions, 113 | passes.parse_label_usage, 114 | 115 | passes.reduce, 116 | passes.debug 117 | ] 118 | 119 | 120 | def usage(): 121 | print("usage: ") 122 | 123 | 124 | def run_pipeline(code, pipeline, persist = {}): 125 | c = code 126 | 127 | for fn in pipeline: 128 | c = fn(c, persist) 129 | 130 | return c 131 | 132 | 133 | def run(): 134 | # Check for valid cmdline parameters. 135 | if len(sys.argv) > 1 and len(sys.argv) < 4: 136 | inf = sys.argv[1] 137 | ouf = sys.argv[2] 138 | 139 | else: 140 | usage() 141 | return -1; 142 | 143 | # Open input file. 144 | with open(inf, 'r') as f: 145 | code = f.read() 146 | 147 | # If there is no code in the file, raise an error. 148 | if len(code) == 0 or code.isspace(): 149 | raise ValueError("Empty input file!") 150 | 151 | # If all is good, run the compiler and return bytecode. 152 | bytecode = bytearray(run_pipeline(code, FUNCTIONS, PERSIST)) 153 | 154 | # Write bytes to output file. 155 | with open(ouf, "wb") as f: 156 | f.write(bytecode) 157 | 158 | 159 | if __name__ == "__main__": 160 | run() 161 | 162 | -------------------------------------------------------------------------------- /compiler/passes.py: -------------------------------------------------------------------------------- 1 | import copy 2 | import codecs 3 | 4 | 5 | def strip_single_comments(code, persist): 6 | code = code.split('\n'); 7 | 8 | for i, line in enumerate(code): 9 | if "//" in line: 10 | line = line.split("//")[0] 11 | 12 | code[i] = line 13 | 14 | return '\n'.join(code) 15 | 16 | 17 | def strip_multi_comments(code, persist): 18 | new_code = "" 19 | in_comment = False 20 | i = 0 21 | 22 | while i < len(code): 23 | char = code[i] 24 | 25 | # Start of comment and not already inside a comment. 26 | if char[i:i+1] == "/*" and not in_comment: 27 | in_comment = True 28 | 29 | 30 | # End of comment and already inside a comment. 31 | elif char[i:i+1] == "*/" and in_comment: 32 | in_comment = False 33 | i += 3 34 | continue 35 | 36 | # Only append characters _not_ inside the comment. 37 | if not in_comment: 38 | new_code += char 39 | 40 | i += 1 41 | 42 | return new_code 43 | 44 | 45 | def strip_comments(code, persist): 46 | code = strip_single_comments(code, persist) 47 | code = strip_multi_comments(code, persist) 48 | 49 | return code 50 | 51 | 52 | def format_statements(code, persist): 53 | code = code.split(';')[:-1] 54 | 55 | for i, statement in enumerate(code): 56 | code[i] = statement.strip().split("->") 57 | code[i] = [x.strip() for x in code[i]] 58 | 59 | return code 60 | 61 | 62 | def format_arguments(statements, persist): 63 | for i, statement in enumerate(statements): 64 | if len(statements[i]) > 1: 65 | args = statements[i][1] 66 | args = args[1:-1] 67 | args = args.split(',') 68 | 69 | for x, arg in enumerate(args): 70 | arg = arg.strip() 71 | 72 | if arg.isdigit(): 73 | arg = int(arg) 74 | 75 | args[x] = arg 76 | 77 | statements[i][1] = args 78 | 79 | return statements 80 | 81 | 82 | def fill_empty_arguments(statements, persist): 83 | for i, token in enumerate(statements): 84 | if len(token) == 1: 85 | statements[i].append([]) 86 | 87 | return statements 88 | 89 | 90 | def tokenise_statements(statements, persist): 91 | tokens = [] 92 | 93 | for statement in statements: 94 | op, args = statement 95 | token = {} 96 | 97 | if op[:2] == "::": 98 | token = copy.deepcopy(persist["token_type"]) 99 | 100 | token["type"] = persist["dir_typename"] 101 | token["body"]["name"] = op[2:] 102 | token["body"]["args"] = args 103 | 104 | else: 105 | token = copy.deepcopy(persist["token_type"]) 106 | 107 | token["type"] = persist["op_typename"] 108 | token["body"]["name"] = op 109 | token["body"]["args"] = args 110 | 111 | tokens.append(token) 112 | 113 | return tokens 114 | 115 | 116 | def match_token_ids(tokens, persist): 117 | for i, token in enumerate(tokens): 118 | if token["type"] == persist["op_typename"]: 119 | token["body"]["name"] = persist["opcodes"][token["body"]["name"].upper()] 120 | 121 | elif token["type"] == persist["dir_typename"]: 122 | token["body"]["name"] = persist["directives"][token["body"]["name"].upper()] 123 | 124 | return tokens 125 | 126 | 127 | def is_char(arg): 128 | char = codecs.decode(arg, "unicode_escape") 129 | 130 | if char[::len(char) - 1] == "''": 131 | if len(char[1:-1]) == 1: 132 | return True 133 | 134 | return False 135 | 136 | 137 | def is_string(arg): 138 | char = codecs.decode(arg, "unicode_escape") 139 | 140 | if char[::len(char) - 1] == '""': 141 | if len(char[1:-1]) > 1: 142 | return True 143 | 144 | return False 145 | 146 | 147 | def tokenise_args(tokens, persist): 148 | for i, token in enumerate(tokens): 149 | args = token["body"]["args"] 150 | 151 | for x, arg in enumerate(args): 152 | if isinstance(arg, int): 153 | args[x] = { 154 | "type" : persist["number_typename"], 155 | "value" : arg 156 | } 157 | 158 | else: 159 | if is_char(arg): 160 | args[x] = { 161 | "type" : persist["char_typename"], 162 | "value" : arg 163 | } 164 | 165 | elif is_string(arg): 166 | args[x] = { 167 | "type" : persist["string_typename"], 168 | "value" : arg 169 | } 170 | 171 | else: 172 | args[x] = { 173 | "type" : persist["label_typename"], 174 | "value" : arg 175 | } 176 | 177 | tokens[i]["body"]["args"] = args 178 | 179 | return tokens 180 | 181 | 182 | def parse_strings(tokens, persist): 183 | new_tokens = [] 184 | 185 | for token in tokens: 186 | if token["type"] == persist["op_typename"]: 187 | args = token["body"]["args"] 188 | new_token = token 189 | contains_string = False 190 | 191 | for i, arg in enumerate(args): 192 | if arg["type"] == persist["string_typename"]: 193 | contains_string = True 194 | 195 | for char in codecs.decode( 196 | arg["value"][1:-1], 197 | "unicode_escape" 198 | ): 199 | char = char.encode('unicode_escape').decode() 200 | new_token = copy.deepcopy(token) 201 | 202 | new_token["body"]["args"][i]["type"] = persist["char_typename"] 203 | new_token["body"]["args"][i]["value"] = "'{}'".format(char) 204 | 205 | new_tokens.append(new_token) 206 | 207 | if not contains_string: 208 | new_tokens.append(token) 209 | 210 | else: 211 | new_tokens.append(token) 212 | 213 | return new_tokens 214 | 215 | 216 | def parse_chars(tokens, persist): 217 | for i, token in enumerate(tokens): 218 | if token["type"] == persist["op_typename"]: 219 | args = token["body"]["args"] 220 | 221 | for x, arg in enumerate(args): 222 | if arg["type"] == persist["char_typename"]: 223 | char = codecs.decode(arg["value"][1:-1], "unicode_escape") 224 | args[x]["value"] = char 225 | 226 | token["body"]["args"] = args 227 | 228 | return tokens 229 | 230 | 231 | def encode_chars(tokens, persist): 232 | for i, token in enumerate(tokens): 233 | if token["type"] == persist["op_typename"]: 234 | args = token["body"]["args"] 235 | 236 | for x, arg in enumerate(args): 237 | if arg["type"] == persist["char_typename"]: 238 | args[x]["value"] = ord(arg["value"]) 239 | 240 | token["body"]["args"] = args 241 | 242 | return tokens 243 | 244 | 245 | def find_label_positions(tokens, persist): 246 | labels = {} 247 | opcodes = [] 248 | 249 | bytes_so_far = 0 250 | 251 | for token in tokens: 252 | if token["type"] == persist["dir_typename"]: 253 | for arg in token["body"]["args"]: 254 | labels[arg["value"]] = bytes_so_far 255 | 256 | elif token["type"] == persist["op_typename"]: 257 | bytes_so_far += (1 + len(token["body"]["args"])) 258 | opcodes.append(token) 259 | 260 | persist["labels"] = labels 261 | 262 | return opcodes 263 | 264 | 265 | def parse_label_usage(tokens, persist): 266 | for i, token in enumerate(tokens): 267 | if token["type"] == persist["op_typename"]: 268 | args = token["body"]["args"] 269 | 270 | for x, arg in enumerate(args): 271 | if arg["type"] == persist["label_typename"]: 272 | #print(token, arg) 273 | args[x]["value"] = persist["labels"][arg["value"]] 274 | 275 | token["body"]["args"] = args 276 | 277 | return tokens 278 | 279 | 280 | def reduce(tokens, persist): 281 | bytecode = [] 282 | 283 | for token in tokens: 284 | op = token["body"]["name"] 285 | args = token["body"]["args"] 286 | 287 | bytecode.append(op) 288 | 289 | for arg in args: 290 | bytecode.append(arg["value"]) 291 | 292 | return bytecode 293 | 294 | 295 | def debug(tokens, persist): 296 | print(tokens) 297 | return tokens -------------------------------------------------------------------------------- /docs/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jackojc/oldwotpp/bdb38b71c2ac016cdf1619040b7b2e46f87d4849/docs/logo.png -------------------------------------------------------------------------------- /docs/ops.md: -------------------------------------------------------------------------------- 1 | # Wot++ VM design specification. 2 | 3 | ## Types/Classes. 4 | 5 | ### Object (A union of multiple data types.): 6 | > Holds a primitive value. 7 | - char (int8_t) 8 | - int (int32) 9 | - ptr (void\*) 10 | 11 | 12 | ### Stack: 13 | > A LIFO container that supports pushing and popping. 14 | 15 | 16 | ### Heap: 17 | > A container that allows data to be stored in any order the user desires. 18 | A couple of example containers that fulfill this role: 19 | 20 | - Array 21 | - Linked list 22 | 23 | 24 | 25 | 26 | ## Memory model/Structures. 27 | 28 | 29 | 30 | ### Stacks: 31 | > Operand data. 32 | 33 | ##### Implementation details: 34 | - Stacks must be at least 64 [Objects](./#object-a-union-of-multiple-data-types) in size. 35 | - A minimum of 8 stacks must be available to the user. 36 | 37 | As an example implementation consider the following: 38 | - A = Global data 39 | - B = Function arguments 40 | - C = Return values 41 | 42 | _whereby `A` stores all generic global data._ 43 | 44 | _whereby `B` stores all arguments to be passed into a function._ 45 | 46 | _whereby `C` stores all output values of a function after transformation._ 47 | 48 | 49 | 50 | 51 | 52 | ### Heap: 53 | > A collection of [Objects](./#object-a-union-of-multiple-data-types). 54 | 55 | ##### Implementation details: 56 | - Heap must be at least 1024 [Objects](./#object-a-union-of-multiple-data-types) in size. 57 | 58 | 59 | 60 | 61 | 62 | 63 | ## Operations. 64 | 65 | ##### Note 1: 66 | - The operations below mostly have to be implemented both for characters _and_ integers. 67 | 68 | ##### Note 2: 69 | - STACK_ID = The stack in which to perform the operation. 70 | - N = Range of elements to perform the operation on. 71 | - X = Literal value to use in operation. 72 | - ADDR = Address from where to get a value or put a value. 73 | 74 | ### Stack manipulation operators. 75 | | Operation | Arguments | Explanation | 76 | | ----------- | ----------- | ----------- | 77 | | PSHL | STACK_ID, X | Push a literal to the stack. | 78 | | PUSH | STACK_ID, ADDR, N | Push an object to the stack. | 79 | | STOR | STACK_ID, ADDR, N | Pop the top item on the stack and save it in the heap. | 80 | | POP | STACK_ID, N | Discard the top value of the stack. | 81 | 82 | ### I/O operators. 83 | | Operation | Arguments | Explanation | 84 | | ----------- | ----------- | ----------- | 85 | | PRNT | STACK_ID, N | Print an ASCII value. | 86 | | EMIT | STACK_ID, N | Print a raw value. | 87 | | PRNL | X | Print a literal ASCII value. | 88 | | EMTL | X | Print a literal raw value. | 89 | 90 | ### Group mathematical operators. 91 | | Operation | Arguments | Explanation | 92 | | ----------- | ----------- | ----------- | 93 | | SUM | STACK_ID, N | Get the sum of a range of elements. | 94 | | PROD | STACK_ID, N | Get the product of a range of elements. | 95 | 96 | ### Mathematical operators. 97 | | Operation | Arguments | Explanation | 98 | | ----------- | ----------- | ----------- | 99 | | ADD | STACK_ID | Consume the top two items on the stack and ADD them. | 100 | | SUB | STACK_ID | Consume the top two items on the stack and SUBTRACT them. | 101 | | MUL | STACK_ID | Consume the top two items on the stack and MULTIPLY them. | 102 | | DIV | STACK_ID | Consume the top two items on the stack and DIVIDE them. | 103 | | MOD | STACK_ID | Consume the top two items on the stack and apply the MODULUS operator to them. | 104 | | NEG | STACK_ID | Consume the top item of the stack and NEGATE it. | 105 | | INCR | STACK_ID, X | Increment the item on top of the stack. | 106 | | DECR | STACK_ID, X | Decrement the item on top of the stack. | 107 | 108 | ### Bitshift operators. 109 | | Operation | Arguments | Explanation | 110 | | ----------- | ----------- | ----------- | 111 | | LSHF | STACK_ID | Shift the item on top of the stack to the left by a number of bits. | 112 | | RSHF | STACK_ID | Shift the item on top of the stack to the right by a number of bits. | 113 | | LROT | STACK_ID | Rotate the item on top of the stack to the left by a number of bits. | 114 | | RROT | STACK_ID | Rotate the item on top of the stack to the right by a number of bits. | 115 | 116 | ### Logical operators. 117 | | Operation | Arguments | Explanation | 118 | | ----------- | ----------- | ----------- | 119 | | AND | STACK_ID | Consume the top two elements on the stack and AND them. | 120 | | OR | STACK_ID | Consume the top two elements on the stack and OR them. | 121 | | XOR | STACK_ID | Consume the top two elements on the stack and XOR them. | 122 | | NOT | STACK_ID | Consume the top item of the stack and NOT it. | 123 | 124 | ### Group comparison operators. 125 | | Operation | Arguments | Explanation | 126 | | ----------- | ----------- | ----------- | 127 | | ALL | STACK_ID, N | Compare a range of elements to see if they are ALL true. | 128 | | ANY | STACK_ID, N | Compare a range of elements to see if ANY are true. | 129 | 130 | ### Comparison operators. 131 | | Operation | Arguments | Explanation | 132 | | ----------- | ----------- | ----------- | 133 | | CMEQ | STACK_ID | Check if the top two elements are the same as eachother. | 134 | | CMNL | STACK_ID | Check if the top two elements are not the same as eachother. | 135 | | CMLT | STACK_ID | Check if the top element is less than the top-1 element. | 136 | | CMMT | STACK_ID | Check if the top element is more than the top-1 element. | 137 | 138 | ### Global jump operators. 139 | | Operation | Arguments | Explanation | 140 | | ----------- | ----------- | ----------- | 141 | | JUMP | X | Unconditionally jump to an address in the code. | 142 | | JPEQ | STACK_ID, X | Jump to an address in code if the top element in the stack is TRUE. | 143 | | JPNL | STACK_ID, X | Jump to an address in code if the top element in the stack is FALSE. | 144 | 145 | ### Relative jump operators. 146 | | Operation | Arguments | Explanation | 147 | | ----------- | ----------- | ----------- | 148 | | JMPR | X | Jump to an address in code relative to the current address. | 149 | | JREQ | STACK_ID, X | Jump to an address in code relative to the current address if the top element in the stack is TRUE. | 150 | | JRNL | STACK_ID, X | Jump to an address in code relative to the current address if the top element in the stack is FALSE. | 151 | 152 | ### Function operators. 153 | | Operation | Arguments | Explanation | 154 | | ----------- | ----------- | ----------- | 155 | | CALL | STACK_ID, X | Jump to X and save current instruction pointer in the stack. | 156 | | RET | STACK_ID | Jump to the top value in the stack. | 157 | 158 | ### Other operators. 159 | | Operation | Arguments | Explanation | 160 | | ----------- | ----------- | ----------- | 161 | | HALT | N/A | Halt execution of the code. | 162 | | NOOP | N/A | No operation, dummy instruction. | -------------------------------------------------------------------------------- /docs/ops_cheatsheet.md: -------------------------------------------------------------------------------- 1 | ``` 2 | PSHL [STACK_ID, X] 3 | PUSH [STACK_ID, ADDR, N] 4 | STOR [STACK_ID, ADDR, N] 5 | POP [STACK_ID, N] 6 | 7 | PRNT [STACK_ID, N] 8 | EMIT [STACK_ID, N] 9 | PRNL [X] 10 | EMTL [X] 11 | 12 | SUM [STACK_ID, N] 13 | PROD [STACK_ID, N] 14 | 15 | ADD [STACK_ID] 16 | SUB [STACK_ID] 17 | MUL [STACK_ID] 18 | DIV [STACK_ID] 19 | MOD [STACK_ID] 20 | NEG [STACK_ID] 21 | INCR [STACK_ID, X] 22 | DECR [STACK_ID, X] 23 | 24 | LSHF [STACK_ID] 25 | RSHF [STACK_ID] 26 | LROT [STACK_ID] 27 | RROT [STACK_ID] 28 | 29 | AND [STACK_ID] 30 | OR [STACK_ID] 31 | XOR [STACK_ID] 32 | NOT [STACK_ID] 33 | 34 | ALL [STACK_ID, N] 35 | ANY [STACK_ID, N] 36 | 37 | CMEQ [STACK_ID] 38 | CMNL [STACK_ID] 39 | CMLT [STACK_ID] 40 | CMMT [STACK_ID] 41 | 42 | JUMP [X] 43 | JPEQ [STACK_ID, X] 44 | JPNL [STACK_ID, X] 45 | 46 | JMPR [X] 47 | JREQ [STACK_ID, X] 48 | JRNL [STACK_ID, X] 49 | 50 | CALL [STACK_ID, X] 51 | RET [STACK_ID] 52 | 53 | HALT [] 54 | NOOP [] 55 | ``` -------------------------------------------------------------------------------- /impl/make_ops.h: -------------------------------------------------------------------------------- 1 | #ifndef IMPL_MAKE_OPS_H // personal fuck you to nullcat 2 | #define IMPL_MAKE_OPS_H 3 | 4 | 5 | wotpp::op_group make_ops() { 6 | // Create array for instructions. 7 | wotpp::op_group ops; 8 | 9 | // Fill operations array with default instruction. 10 | // This means if it encounters an instruction it 11 | // doesn't understand, it will skip it. 12 | std::fill(ops.begin(), ops.end(), op_noop); 13 | 14 | int i = 0; 15 | 16 | // Setup operations. 17 | ops[i++] = op_pshl; 18 | ops[i++] = op_push; 19 | ops[i++] = op_stor; 20 | ops[i++] = op_pop; 21 | 22 | ops[i++] = op_prnt; 23 | ops[i++] = op_emit; 24 | ops[i++] = op_prnl; 25 | ops[i++] = op_emtl; 26 | 27 | ops[i++] = op_sum; 28 | ops[i++] = op_prod; 29 | 30 | ops[i++] = op_add; 31 | ops[i++] = op_sub; 32 | ops[i++] = op_mul; 33 | ops[i++] = op_div; 34 | ops[i++] = op_mod; 35 | ops[i++] = op_neg; 36 | ops[i++] = op_incr; 37 | ops[i++] = op_decr; 38 | 39 | ops[i++] = op_lshf; 40 | ops[i++] = op_rshf; 41 | ops[i++] = op_lrot; 42 | ops[i++] = op_rrot; 43 | 44 | ops[i++] = op_and; 45 | ops[i++] = op_or; 46 | ops[i++] = op_xor; 47 | ops[i++] = op_not; 48 | 49 | ops[i++] = op_all; 50 | ops[i++] = op_any; 51 | 52 | ops[i++] = op_cmeq; 53 | ops[i++] = op_cmnl; 54 | ops[i++] = op_cmlt; 55 | ops[i++] = op_cmmt; 56 | 57 | ops[i++] = op_jump; 58 | ops[i++] = op_jpeq; 59 | ops[i++] = op_jpnl; 60 | 61 | ops[i++] = op_jmpr; 62 | ops[i++] = op_jreq; 63 | ops[i++] = op_jrnl; 64 | 65 | ops[i++] = op_call; 66 | ops[i++] = op_ret; 67 | 68 | ops[i++] = op_halt; 69 | ops[i++] = op_noop; 70 | 71 | return ops; 72 | } 73 | 74 | 75 | #endif -------------------------------------------------------------------------------- /impl/ops.h: -------------------------------------------------------------------------------- 1 | #ifndef IMPL_OPS_H 2 | #define IMPL_OPS_H 3 | 4 | 5 | #define OPERATION(name) void name(wotpp::instr_ptr& ip, wotpp::instr_ptr initial_ip, wotpp::stack_group& stacks, wotpp::heap& heap, bool& running) 6 | 7 | 8 | #include "ops/stack_manipulation.h" 9 | 10 | #include "ops/io.h" 11 | 12 | #include "ops/group_math.h" 13 | #include "ops/math.h" 14 | 15 | #include "ops/bitshift.h" 16 | #include "ops/logical.h" 17 | 18 | #include "ops/group_comparison.h" 19 | #include "ops/comparison.h" 20 | 21 | #include "ops/jump.h" 22 | #include "ops/rel_jump.h" 23 | #include "ops/functions.h" 24 | 25 | #include "ops/other.h" 26 | 27 | #include "make_ops.h" 28 | 29 | 30 | #endif -------------------------------------------------------------------------------- /impl/ops/bitshift.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | 4 | // Helper functions 5 | int8_t rotl8b(int8_t x, int8_t n) { 6 | assert(n < 8); 7 | if (!n) return x; 8 | return (x << n) | (x >> (8 - n)); 9 | } 10 | 11 | 12 | int8_t rotr8b(int8_t x, int8_t n) { 13 | assert(n < 8); 14 | if (!n) return x; 15 | return (x >> n) | (x << (8 - n)); 16 | } 17 | 18 | 19 | // Operations 20 | OPERATION(op_lshf) { 21 | uint8_t stack_id = *(ip + 1); 22 | uint8_t shift = *(ip + 2); 23 | auto o = stacks[stack_id].pop(); 24 | 25 | o.chr <<= shift; 26 | 27 | stacks[stack_id].push(o); 28 | 29 | ip += 3; 30 | } 31 | 32 | 33 | OPERATION(op_rshf) { 34 | uint8_t stack_id = *(ip + 1); 35 | uint8_t shift = *(ip + 2); 36 | auto o = stacks[stack_id].pop(); 37 | 38 | o.chr >>= shift; 39 | 40 | stacks[stack_id].push(o); 41 | 42 | ip += 3; 43 | } 44 | 45 | 46 | OPERATION(op_lrot) { 47 | uint8_t stack_id = *(ip + 1); 48 | uint8_t shift = *(ip + 2); 49 | auto o = stacks[stack_id].pop(); 50 | 51 | o.chr = rotl8b(o.chr, shift); 52 | 53 | stacks[stack_id].push(o); 54 | 55 | ip += 3; 56 | } 57 | 58 | 59 | OPERATION(op_rrot) { 60 | uint8_t stack_id = *(ip + 1); 61 | uint8_t shift = *(ip + 2); 62 | auto o = stacks[stack_id].pop(); 63 | 64 | o.chr = rotr8b(o.chr, shift); 65 | 66 | stacks[stack_id].push(o); 67 | 68 | ip += 3; 69 | } -------------------------------------------------------------------------------- /impl/ops/comparison.h: -------------------------------------------------------------------------------- 1 | OPERATION(op_cmeq) { 2 | uint8_t stack_id = *(ip + 1); 3 | auto ab = stacks[stack_id].pop(2); 4 | 5 | wotpp::obj_t o; 6 | 7 | o.type = wotpp::TYPE::CHR; 8 | o.chr = ab[0].chr == ab[1].chr; 9 | 10 | stacks[stack_id].push(o); 11 | 12 | ip += 2; 13 | } 14 | 15 | 16 | OPERATION(op_cmnl) { 17 | uint8_t stack_id = *(ip + 1); 18 | auto ab = stacks[stack_id].pop(2); 19 | 20 | wotpp::obj_t o; 21 | 22 | o.type = wotpp::TYPE::CHR; 23 | o.chr = ab[0].chr != ab[1].chr; 24 | 25 | stacks[stack_id].push(o); 26 | 27 | ip += 2; 28 | } 29 | 30 | 31 | OPERATION(op_cmlt) { 32 | uint8_t stack_id = *(ip + 1); 33 | auto ab = stacks[stack_id].pop(2); 34 | 35 | wotpp::obj_t o; 36 | 37 | o.type = wotpp::TYPE::CHR; 38 | o.chr = ab[0].chr < ab[1].chr; 39 | 40 | stacks[stack_id].push(o); 41 | 42 | ip += 2; 43 | } 44 | 45 | 46 | OPERATION(op_cmmt) { 47 | uint8_t stack_id = *(ip + 1); 48 | auto ab = stacks[stack_id].pop(2); 49 | 50 | wotpp::obj_t o; 51 | 52 | o.type = wotpp::TYPE::CHR; 53 | o.chr = ab[0].chr > ab[1].chr; 54 | 55 | stacks[stack_id].push(o); 56 | 57 | ip += 2; 58 | } 59 | -------------------------------------------------------------------------------- /impl/ops/functions.h: -------------------------------------------------------------------------------- 1 | OPERATION(op_call) { 2 | uint8_t stack_id = *(ip + 1); 3 | int8_t addr = *(ip + 2); 4 | 5 | wotpp::obj_t o; 6 | 7 | // save current instruction pointer to stack. 8 | o.type = wotpp::TYPE::PTR; 9 | o.ptr = static_cast(ip + 3); 10 | 11 | stacks[stack_id].push(o); 12 | 13 | ip = initial_ip + addr; 14 | } 15 | 16 | 17 | OPERATION(op_ret) { 18 | uint8_t stack_id = *(ip + 1); 19 | wotpp::obj_t o = stacks[stack_id].pop(); 20 | 21 | ip = static_cast(o.ptr); 22 | } -------------------------------------------------------------------------------- /impl/ops/group_comparison.h: -------------------------------------------------------------------------------- 1 | OPERATION(op_all) { 2 | uint8_t stack_id = *(ip + 1); 3 | uint8_t n = *(ip + 2); 4 | 5 | wotpp::obj_t o; 6 | 7 | o.type = wotpp::TYPE::CHR; 8 | o.chr = true; 9 | 10 | for (int i = 0; i < n; ++i) { 11 | wotpp::obj_t x = stacks[stack_id].pop(); 12 | 13 | if (!x.chr) { 14 | o.chr = false; 15 | stacks[stack_id].push(o); 16 | } 17 | } 18 | 19 | ip += 3; 20 | } 21 | 22 | 23 | OPERATION(op_any) { 24 | uint8_t stack_id = *(ip + 1); 25 | uint8_t n = *(ip + 2); 26 | 27 | wotpp::obj_t o; 28 | 29 | o.type = wotpp::TYPE::CHR; 30 | o.chr = false; 31 | 32 | for (int i = 0; i < n; ++i) { 33 | wotpp::obj_t x = stacks[stack_id].pop(); 34 | 35 | if (x.chr) { 36 | o.chr = true; 37 | stacks[stack_id].push(o); 38 | } 39 | } 40 | 41 | ip += 3; 42 | } -------------------------------------------------------------------------------- /impl/ops/group_math.h: -------------------------------------------------------------------------------- 1 | OPERATION(op_sum) { 2 | uint8_t stack_id = *(ip + 1); 3 | uint8_t n = *(ip + 2); 4 | 5 | int8_t tally = 0; 6 | 7 | for (int i = 0; i < n; ++i) { 8 | wotpp::obj_t o = stacks[stack_id].pop(); 9 | 10 | tally += o.chr; 11 | } 12 | 13 | wotpp::obj_t o; 14 | 15 | o.type = wotpp::TYPE::CHR; 16 | o.chr = tally; 17 | 18 | stacks[stack_id].push(o); 19 | 20 | ip += 3; 21 | } 22 | 23 | 24 | OPERATION(op_prod) { 25 | uint8_t stack_id = *(ip + 1); 26 | uint8_t n = *(ip + 2); 27 | 28 | int8_t tally = 0; 29 | 30 | for (int i = 0; i < n; ++i) { 31 | wotpp::obj_t o = stacks[stack_id].pop(); 32 | 33 | tally *= o.chr; 34 | } 35 | 36 | wotpp::obj_t o; 37 | 38 | o.type = wotpp::TYPE::CHR; 39 | o.chr = tally; 40 | 41 | stacks[stack_id].push(o); 42 | 43 | ip += 3; 44 | } -------------------------------------------------------------------------------- /impl/ops/io.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | 4 | OPERATION(op_emit) { 5 | uint8_t stack_id = *(ip + 1); 6 | uint8_t n = *(ip + 2); 7 | 8 | for (int i = 0; i < n; ++i) { 9 | wotpp::obj_t o = stacks[stack_id].pop(); 10 | std::printf("%i", o.chr); 11 | } 12 | 13 | ip += 3; 14 | } 15 | 16 | 17 | OPERATION(op_prnt) { 18 | uint8_t stack_id = *(ip + 1); 19 | uint8_t n = *(ip + 2); 20 | 21 | for (int i = 0; i < n; ++i) { 22 | wotpp::obj_t o = stacks[stack_id].pop(); 23 | std::putchar(o.chr); 24 | } 25 | 26 | ip += 3; 27 | } 28 | 29 | 30 | OPERATION(op_emtl) { 31 | int8_t x = *(ip + 1); 32 | 33 | std::printf("%i", x); 34 | 35 | ip += 2; 36 | } 37 | 38 | 39 | OPERATION(op_prnl) { 40 | int8_t x = *(ip + 1); 41 | 42 | std::putchar(x); 43 | 44 | ip += 2; 45 | } -------------------------------------------------------------------------------- /impl/ops/jump.h: -------------------------------------------------------------------------------- 1 | OPERATION(op_jump) { 2 | int8_t addr = *(ip + 1); 3 | 4 | ip = initial_ip + addr; 5 | } 6 | 7 | 8 | OPERATION(op_jpeq) { 9 | uint8_t stack_id = *(ip + 1); 10 | int8_t addr = *(ip + 2); 11 | wotpp::obj_t o = stacks[stack_id].pop(); 12 | 13 | if (o.chr) 14 | ip = initial_ip + addr; 15 | else 16 | ip += 3; 17 | } 18 | 19 | 20 | OPERATION(op_jpnl) { 21 | uint8_t stack_id = *(ip + 1); 22 | int8_t addr = *(ip + 2); 23 | wotpp::obj_t o = stacks[stack_id].pop(); 24 | 25 | if (!o.chr) 26 | ip = initial_ip + addr; 27 | else 28 | ip += 3; 29 | } 30 | -------------------------------------------------------------------------------- /impl/ops/logical.h: -------------------------------------------------------------------------------- 1 | OPERATION(op_and) { 2 | uint8_t stack_id = *(ip + 1); 3 | auto ab = stacks[stack_id].pop(2); 4 | 5 | wotpp::obj_t o; 6 | 7 | o.type = wotpp::TYPE::CHR; 8 | o.chr = ab[0].chr & ab[1].chr; 9 | 10 | stacks[stack_id].push(o); 11 | 12 | ip += 2; 13 | } 14 | 15 | 16 | OPERATION(op_or) { 17 | uint8_t stack_id = *(ip + 1); 18 | auto ab = stacks[stack_id].pop(2); 19 | 20 | wotpp::obj_t o; 21 | 22 | o.type = wotpp::TYPE::CHR; 23 | o.chr = ab[0].chr | ab[1].chr; 24 | 25 | stacks[stack_id].push(o); 26 | 27 | ip += 2; 28 | } 29 | 30 | 31 | OPERATION(op_xor) { 32 | uint8_t stack_id = *(ip + 1); 33 | auto ab = stacks[stack_id].pop(2); 34 | 35 | wotpp::obj_t o; 36 | 37 | o.type = wotpp::TYPE::CHR; 38 | o.chr = ab[0].chr ^ ab[1].chr; 39 | 40 | stacks[stack_id].push(o); 41 | 42 | ip += 2; 43 | } 44 | 45 | 46 | OPERATION(op_not) { 47 | uint8_t stack_id = *(ip + 1); 48 | auto o = stacks[stack_id].pop(); 49 | 50 | o.chr = ~o.chr; 51 | 52 | stacks[stack_id].push(o); 53 | 54 | ip += 2; 55 | } -------------------------------------------------------------------------------- /impl/ops/math.h: -------------------------------------------------------------------------------- 1 | OPERATION(op_add) { 2 | uint8_t stack_id = *(ip + 1); 3 | auto ab = stacks[stack_id].pop(2); 4 | 5 | wotpp::obj_t o; 6 | 7 | o.type = wotpp::TYPE::CHR; 8 | o.chr = ab[0].chr + ab[1].chr; 9 | 10 | stacks[stack_id].push(o); 11 | 12 | ip += 2; 13 | } 14 | 15 | 16 | OPERATION(op_sub) { 17 | uint8_t stack_id = *(ip + 1); 18 | auto ab = stacks[stack_id].pop(2); 19 | 20 | wotpp::obj_t o; 21 | 22 | o.type = wotpp::TYPE::CHR; 23 | o.chr = ab[0].chr - ab[1].chr; 24 | 25 | stacks[stack_id].push(o); 26 | 27 | ip += 2; 28 | } 29 | 30 | 31 | OPERATION(op_mul) { 32 | uint8_t stack_id = *(ip + 1); 33 | auto ab = stacks[stack_id].pop(2); 34 | 35 | wotpp::obj_t o; 36 | 37 | o.type = wotpp::TYPE::CHR; 38 | o.chr = ab[0].chr * ab[1].chr; 39 | 40 | stacks[stack_id].push(o); 41 | 42 | ip += 2; 43 | } 44 | 45 | 46 | OPERATION(op_div) { 47 | uint8_t stack_id = *(ip + 1); 48 | auto ab = stacks[stack_id].pop(2); 49 | 50 | wotpp::obj_t o; 51 | 52 | o.type = wotpp::TYPE::CHR; 53 | o.chr = ab[0].chr / ab[1].chr; 54 | 55 | stacks[stack_id].push(o); 56 | 57 | ip += 2; 58 | } 59 | 60 | 61 | OPERATION(op_mod) { 62 | uint8_t stack_id = *(ip + 1); 63 | auto ab = stacks[stack_id].pop(2); 64 | 65 | wotpp::obj_t o; 66 | 67 | o.type = wotpp::TYPE::CHR; 68 | o.chr = ab[0].chr % ab[1].chr; 69 | 70 | stacks[stack_id].push(o); 71 | 72 | ip += 2; 73 | } 74 | 75 | 76 | OPERATION(op_neg) { 77 | uint8_t stack_id = *(ip + 1); 78 | wotpp::obj_t x = stacks[stack_id].pop(); 79 | 80 | x.chr = -x.chr; 81 | 82 | stacks[stack_id].push(x); 83 | 84 | ip += 2; 85 | } 86 | 87 | 88 | OPERATION(op_incr) { 89 | uint8_t stack_id = *(ip + 1); 90 | uint8_t x = *(ip + 2); 91 | wotpp::obj_t o = stacks[stack_id].pop(); 92 | 93 | o.chr += x; 94 | 95 | stacks[stack_id].push(o); 96 | 97 | ip += 3; 98 | } 99 | 100 | 101 | OPERATION(op_decr) { 102 | uint8_t stack_id = *(ip + 1); 103 | uint8_t x = *(ip + 2); 104 | wotpp::obj_t o = stacks[stack_id].pop(); 105 | 106 | o.chr -= x; 107 | 108 | stacks[stack_id].push(o); 109 | 110 | ip += 3; 111 | } -------------------------------------------------------------------------------- /impl/ops/other.h: -------------------------------------------------------------------------------- 1 | // No operation. (skip) 2 | OPERATION(op_noop) { 3 | ip++; 4 | } 5 | 6 | 7 | // When encountered, halt the machine and exit. 8 | OPERATION(op_halt) { 9 | running = false; 10 | } -------------------------------------------------------------------------------- /impl/ops/rel_jump.h: -------------------------------------------------------------------------------- 1 | OPERATION(op_jmpr) { 2 | int8_t x = *(ip + 1); 3 | 4 | ip += x; 5 | } 6 | 7 | 8 | OPERATION(op_jreq) { 9 | uint8_t stack_id = *(ip + 1); 10 | int8_t x = *(ip + 2); 11 | wotpp::obj_t o = stacks[stack_id].pop(); 12 | 13 | if (o.chr) 14 | ip += x; 15 | else 16 | ip += 3; 17 | } 18 | 19 | 20 | OPERATION(op_jrnl) { 21 | uint8_t stack_id = *(ip + 1); 22 | int8_t x = *(ip + 2); 23 | wotpp::obj_t o = stacks[stack_id].pop(); 24 | 25 | if (!o.chr) 26 | ip += x; 27 | else 28 | ip += 3; 29 | } 30 | -------------------------------------------------------------------------------- /impl/ops/stack_manipulation.h: -------------------------------------------------------------------------------- 1 | OPERATION(op_pshl) { 2 | uint8_t stack_id = *(ip + 1); 3 | int8_t x = *(ip + 2); 4 | 5 | wotpp::obj_t o; 6 | 7 | o.type = wotpp::TYPE::CHR; 8 | o.chr = x; 9 | 10 | stacks[stack_id].push(o); 11 | 12 | ip += 3; 13 | } 14 | 15 | 16 | OPERATION(op_push) { 17 | uint8_t stack_id = *(ip + 1); 18 | uint8_t addr = *(ip + 2); 19 | uint8_t n = *(ip + 3); 20 | 21 | for (int i = 0; i < n; ++i) { 22 | wotpp::obj_t o; 23 | 24 | o.type = wotpp::TYPE::CHR; 25 | o.chr = heap[addr + i].chr; 26 | 27 | stacks[stack_id].push(o); 28 | } 29 | 30 | ip += 4; 31 | } 32 | 33 | 34 | OPERATION(op_stor) { 35 | uint8_t stack_id = *(ip + 1); 36 | uint8_t addr = *(ip + 2); 37 | uint8_t n = *(ip + 3); 38 | 39 | for (int i = 0; i < n; ++i) { 40 | wotpp::obj_t o = stacks[stack_id].pop(); 41 | heap[addr + i] = o; 42 | } 43 | 44 | ip += 4; 45 | } 46 | 47 | 48 | OPERATION(op_pop) { 49 | uint8_t stack_id = *(ip + 1); 50 | uint8_t n = *(ip + 2); 51 | 52 | for (int i = 0; i < n; ++i) { 53 | stacks[stack_id].pop(); 54 | } 55 | 56 | ip += 3; 57 | } -------------------------------------------------------------------------------- /main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "wotpp/core.h" 5 | #include "wotpp/utils.h" 6 | 7 | #include "impl/ops.h" 8 | 9 | 10 | 11 | 12 | // TODO: 13 | // - Implement every operation for both chars and ints. 14 | 15 | 16 | 17 | 18 | // USAGE MESSAGE 19 | void usage() { 20 | std::cout << "usage: \n"; 21 | } 22 | 23 | 24 | 25 | 26 | 27 | 28 | int main(int argc, const char* argv[]) { 29 | // Load file. 30 | bool success; 31 | std::string code; 32 | 33 | // Make sure the correct number of arguments have been provided. 34 | if (argc != 2) { 35 | usage(); 36 | return -1; 37 | } 38 | 39 | 40 | // Attempt to read a file and check if it was successful. 41 | std::tie(success, code) = wotpp::read_file(argv[1]); 42 | 43 | // If we cannot open the file, show an error. 44 | if (!success) { 45 | std::cerr << "Cannot open file!\n"; 46 | usage(); 47 | return -1; 48 | } 49 | 50 | 51 | 52 | 53 | 54 | // We succeeded in loading the file, now run it. 55 | // Setup the heap. 56 | wotpp::heap heap{4096}; 57 | 58 | // Setup stacks. 59 | wotpp::stack_group stacks({ 60 | wotpp::stack{1024}, 61 | wotpp::stack{256}, 62 | wotpp::stack{256}, 63 | wotpp::stack{256}, 64 | wotpp::stack{256}, 65 | wotpp::stack{256}, 66 | wotpp::stack{256}, 67 | wotpp::stack{256} 68 | }); 69 | 70 | 71 | // Create array for instructions. 72 | wotpp::op_group ops = make_ops(); 73 | 74 | // Run the VM. 75 | // Use some chrono stuff for minor benchmarking. 76 | auto start = std::chrono::high_resolution_clock::now(); 77 | wotpp::execute(stacks, heap, ops, code); // Run the code. 78 | auto end = std::chrono::high_resolution_clock::now(); 79 | 80 | // Show us how quickly the function executed in NS. 81 | std::cout << std::chrono::duration_cast(end - start).count() << "ns" << std::endl; 82 | 83 | return 0; 84 | } -------------------------------------------------------------------------------- /scripts/counter.wot: -------------------------------------------------------------------------------- 1 | // Counter example. 2 | 3 | // Hacky usage of labels to create a sort of enum. 4 | ::STACK_0; 5 | noop; 6 | 7 | 8 | // DATA 9 | pshl -> [STACK_0, 16]; // end. 10 | pshl -> [STACK_0, ONE]; // step. 11 | pshl -> [STACK_0, ZERO]; // start. 12 | stor -> [STACK_0, 240, 3]; // store data. 13 | 14 | 15 | 16 | // PROGRAM 17 | // Compare current value to end value. 18 | ::START; 19 | push -> [STACK_0, 240, 1]; 20 | push -> [STACK_0, 242, 1]; 21 | cmeq -> [STACK_0]; 22 | 23 | 24 | // if they are the same, we are done. 25 | jpeq -> [STACK_0, END]; 26 | 27 | 28 | // add step to current value. 29 | push -> [STACK_0, 240, 2]; 30 | add -> [STACK_0]; 31 | 32 | 33 | stor -> [STACK_0, 244, 1]; // stor new value at index 244 34 | push -> [STACK_0, 240, 1]; // push old value. 35 | emit -> [STACK_0, 1]; // print old value. 36 | push -> [STACK_0, 244, 1]; // push new value. 37 | stor -> [STACK_0, 240, 1]; // store new value and overwrite old value. 38 | 39 | 40 | prnl -> ['\n']; 41 | 42 | 43 | jump -> [START]; // loop back to start. 44 | 45 | 46 | ::END; 47 | halt; // kill the vm. -------------------------------------------------------------------------------- /scripts/functions.wot: -------------------------------------------------------------------------------- 1 | // Function example. 2 | 3 | // Enum: 4 | ::label->[GENERAL]; 5 | noop; 6 | 7 | ::label->[ARGS]; 8 | noop; 9 | 10 | ::label->[RET]; 11 | noop; 12 | 13 | ::label->[RET_PTRS]; 14 | noop; 15 | 16 | 17 | jump->[main]; // jump to entry point. 18 | 19 | 20 | // ADD 21 | ::label->[ADD]; 22 | add -> [ARGS]; // add the 2 numbers in ARGS. 23 | 24 | push -> [GENERAL, 0, 1]; // backup whatever is saved in heap[0]. 25 | 26 | stor -> [ARGS, 0, 1]; // store result in heap[0] temporarily. 27 | push -> [RET, 0, 1]; // push heap[0] to return heap. 28 | 29 | stor -> [GENERAL, 0, 1]; // restore heap[0] backup. 30 | ret -> [RET_PTRS]; 31 | 32 | 33 | 34 | // MAIN 35 | ::label->[main, test]; 36 | pshl -> [ARGS, 5]; 37 | pshl -> [ARGS, 5]; 38 | call -> [RET_PTRS, ADD]; 39 | 40 | stor->[RET, 0, 1]; // temporarily store return in heap[0]. 41 | push->[GENERAL, 0, 1]; // push heap[0] to general. 42 | 43 | prnl->["The answer is: "]; 44 | 45 | emit->[GENERAL, 1]; // emit value in general. 46 | 47 | prnl->['\n']; 48 | 49 | jump -> [exit]; // redundant here, but would be useful if a 50 | // function needed to terminate the vm somewhere else. 51 | 52 | 53 | ::label->[exit]; 54 | halt; -------------------------------------------------------------------------------- /scripts/helloworld.wb: -------------------------------------------------------------------------------- 1 | 2 | !dlroW olleH $ -------------------------------------------------------------------------------- /scripts/helloworld.wot: -------------------------------------------------------------------------------- 1 | // `Hello World!` example. 2 | // Push "Hello World!\n" in reverse order to the stack. 3 | // Print 13 characters from the stack to the terminal. 4 | // Halt the VM. 5 | 6 | PSHL -> [0, 10]; // \n 7 | PSHL -> [0, 33]; // ! 8 | PSHL -> [0, 100]; // d 9 | PSHL -> [0, 108]; // l 10 | PSHL -> [0, 114]; // r 11 | PSHL -> [0, 111]; // o 12 | PSHL -> [0, 87]; // W 13 | 14 | PSHL -> [0, 32]; // ' ' 15 | 16 | PSHL -> [0, 111]; // o 17 | PSHL -> [0, 108]; // l 18 | PSHL -> [0, 108]; // l 19 | PSHL -> [0, 101]; // e 20 | PSHL -> [0, 72]; // H 21 | 22 | PRNT -> [0, 13]; // Print 13 characters from the stack. 23 | HALT; // Halt the VM. -------------------------------------------------------------------------------- /scripts/math.wot: -------------------------------------------------------------------------------- 1 | // Adding example. 2 | 3 | PSHL -> [0, 10]; // Push newline character to the stack. 4 | STOR -> [0, 10, 1]; // Store newline into heap. 5 | 6 | PSHL -> [0, 5]; // Push two literals to the stack. 7 | PSHL -> [0, 5]; 8 | 9 | ADD -> [0]; // Add the top two items of the stack. 10 | STOR -> [0, 0, 1]; // Store the result to the heap at address `0`. 11 | 12 | PUSH -> [0, 0, 1]; 13 | EMIT -> [0, 1]; // Emit the number. 14 | 15 | PUSH -> [0, 10, 1]; // Push the newline constant to the stack. 16 | PRNT -> [0, 1]; // Print the number so we get a newline. 17 | 18 | HALT; // Halt execution (this goes out to my pal pohuing). 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | // Subtraction example. 29 | 30 | PSHL -> [0, 10]; // Push newline character to the stack. 31 | STOR -> [0, 10, 1]; // Store newline into heap. 32 | 33 | PSHL -> [0, 2]; // Push two literals to the stack. 34 | PSHL -> [0, 15]; 35 | 36 | SUB -> [0]; // Subtract the top two items of the stack. 37 | STOR -> [0, 0, 1]; // Store the result to the heap at address `0`. 38 | 39 | PUSH -> [0, 0, 1]; 40 | EMIT -> [0, 1]; // Emit the number. 41 | 42 | PUSH -> [0, 10, 1]; // Push the newline constant to the stack. 43 | PRNT -> [0, 1]; // Print the number so we get a newline. 44 | 45 | HALT; // Halt execution (this goes out to my pal pohuing). 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | // Multiplication example. 56 | 57 | PSHL -> [0, 10]; // Push newline character to the stack. 58 | STOR -> [0, 10, 1]; // Store newline into heap. 59 | 60 | PSHL -> [0, 2]; // Push two literals to the stack. 61 | PSHL -> [0, 15]; 62 | 63 | MUL -> [0]; // Multiply the top two items of the stack. 64 | STOR -> [0, 0, 1]; // Store the result to the heap at address `0`. 65 | 66 | PUSH -> [0, 0, 1]; 67 | EMIT -> [0, 1]; // Emit the number. 68 | 69 | PUSH -> [0, 10, 1]; // Push the newline constant to the stack. 70 | PRNT -> [0, 1]; // Print the number so we get a newline. 71 | 72 | HALT; // Halt execution (this goes out to my pal pohuing). 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | // Division example. 85 | 86 | PSHL -> [0, 10]; // Push newline character to the stack. 87 | STOR -> [0, 10, 1]; // Store newline into heap. 88 | 89 | PSHL -> [0, 2]; // Push two literals to the stack. 90 | PSHL -> [0, 10]; 91 | 92 | DIV -> [0]; // Divide the top two items of the stack. 93 | STOR -> [0, 0, 1]; // Store the result to the heap at address `0`. 94 | 95 | PUSH -> [0, 0, 1]; 96 | EMIT -> [0, 1]; // Emit the number. 97 | 98 | PUSH -> [0, 10, 1]; // Push the newline constant to the stack. 99 | PRNT -> [0, 1]; // Print the number so we get a newline. 100 | 101 | HALT; // Halt execution (this goes out to my pal pohuing). 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | // Modulus example. 114 | 115 | PSHL -> [0, 10]; // Push newline character to the stack. 116 | STOR -> [0, 10, 1]; // Store newline into heap. 117 | 118 | PSHL -> [0, 9]; // Push two literals to the stack. 119 | PSHL -> [0, 10]; 120 | 121 | MOD -> [0]; // Mod the top two items of the stack. 122 | STOR -> [0, 0, 1]; // Store the result to the heap at address `0`. 123 | 124 | PUSH -> [0, 0, 1]; 125 | EMIT -> [0, 1]; // Emit the number. 126 | 127 | PUSH -> [0, 10, 1]; // Push the newline constant to the stack. 128 | PRNT -> [0, 1]; // Print the number so we get a newline. 129 | 130 | HALT; // Halt execution (this goes out to my pal pohuing). 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | // Negation example. 144 | 145 | PSHL -> [0, 10]; // Push newline character to the stack. 146 | STOR -> [0, 10, 1]; // Store newline into heap. 147 | 148 | PSHL -> [0, 67]; // Push a literal to the stack. 149 | 150 | NEG -> [0]; // Negate the top item of the stack. 151 | STOR -> [0, 0, 1]; // Store the result to the heap at address `0`. 152 | 153 | PUSH -> [0, 0, 1]; 154 | EMIT -> [0, 1]; // Emit the number. 155 | 156 | PUSH -> [0, 10, 1]; // Push the newline constant to the stack. 157 | PRNT -> [0, 1]; // Print the number so we get a newline. 158 | 159 | HALT; // Halt execution (this goes out to my pal pohuing). 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | // Increment example. 172 | 173 | PSHL -> [0, 10]; // Push newline character to the stack. 174 | STOR -> [0, 10, 1]; // Store newline into heap. 175 | 176 | PSHL -> [0, 0]; // Push a literal to the stack. 177 | 178 | INCR -> [0, 3]; // Incr the top item of the stack. 179 | INCR -> [0, 2]; // Incr the top item of the stack. 180 | 181 | STOR -> [0, 0, 1]; // Store the result to the heap at address `0`. 182 | 183 | PUSH -> [0, 0, 1]; 184 | EMIT -> [0, 1]; // Emit the number. 185 | 186 | PUSH -> [0, 10, 1]; // Push the newline constant to the stack. 187 | PRNT -> [0, 1]; // Print the number so we get a newline. 188 | 189 | HALT; // Halt execution (this goes out to my pal pohuing). 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | // Decrement example. 202 | 203 | PSHL -> [0, 10]; // Push newline character to the stack. 204 | STOR -> [0, 10, 1]; // Store newline into heap. 205 | 206 | PSHL -> [0, 96]; // Push a literal to the stack. 207 | 208 | DECR -> [0, 30]; // Decr the top item of the stack. 209 | DECR -> [0, 21]; // Decr the top item of the stack. 210 | 211 | STOR -> [0, 0, 1]; // Store the result to the heap at address `0`. 212 | 213 | PUSH -> [0, 0, 1]; 214 | EMIT -> [0, 1]; // Emit the number. 215 | 216 | PUSH -> [0, 10, 1]; // Push the newline constant to the stack. 217 | PRNT -> [0, 1]; // Print the number so we get a newline. 218 | 219 | HALT; // Halt execution (this goes out to my pal pohuing). -------------------------------------------------------------------------------- /scripts/string.wot: -------------------------------------------------------------------------------- 1 | // String example. 2 | ::STACK_0; 3 | noop; 4 | 5 | ::start; 6 | 7 | prnl -> ["Hello World\n"]; 8 | 9 | ::end; 10 | halt; -------------------------------------------------------------------------------- /scripts/test.wot: -------------------------------------------------------------------------------- 1 | // Counter example. 2 | 3 | // Hacky usage of labels to create a sort of enum. 4 | ::label->[STACK_0, ZERO]; 5 | noop; 6 | ::label->[ONE]; 7 | 8 | 9 | // DATA 10 | pshl -> [STACK_0, 16]; // end. 11 | pshl -> [STACK_0, ONE]; // step. 12 | pshl -> [STACK_0, ZERO]; // start. 13 | stor -> [STACK_0, 240, 3]; // store data. 14 | 15 | 16 | 17 | // PROGRAM 18 | // Compare current value to end value. 19 | ::label->[START]; 20 | push -> [STACK_0, 240, 1]; 21 | push -> [STACK_0, 242, 1]; 22 | cmeq -> [STACK_0]; 23 | 24 | 25 | // if they are the same, we are done. 26 | jpeq -> [STACK_0, END]; 27 | 28 | 29 | // add step to current value. 30 | push -> [STACK_0, 240, 2]; 31 | add -> [STACK_0]; 32 | 33 | 34 | stor -> [STACK_0, 244, 1]; // stor new value at index 244 35 | push -> [STACK_0, 240, 1]; // push old value. 36 | emit -> [STACK_0, 1]; // print old value. 37 | push -> [STACK_0, 244, 1]; // push new value. 38 | stor -> [STACK_0, 240, 1]; // store new value and overwrite old value. 39 | 40 | 41 | prnl -> ['\n']; 42 | 43 | 44 | jump -> [START]; // loop back to start. 45 | 46 | 47 | ::label->[END]; 48 | halt; // kill the vm. -------------------------------------------------------------------------------- /wotpp/core.h: -------------------------------------------------------------------------------- 1 | #ifndef WOTPP_CORE_H 2 | #define WOTPP_CORE_H 3 | 4 | 5 | #include "object/object.h" 6 | #include "stack/stack.h" 7 | #include "stack_group/stack_group.h" 8 | #include "vm/vm.h" 9 | 10 | 11 | #endif -------------------------------------------------------------------------------- /wotpp/object/object.cpp: -------------------------------------------------------------------------------- 1 | #ifndef WOTPP_OBJECT_CPP 2 | #define WOTPP_OBJECT_CPP 3 | 4 | 5 | #include "object.h" 6 | 7 | 8 | namespace wotpp { 9 | 10 | } 11 | 12 | 13 | #endif -------------------------------------------------------------------------------- /wotpp/object/object.h: -------------------------------------------------------------------------------- 1 | #ifndef WOTPP_OBJECT_H 2 | #define WOTPP_OBJECT_H 3 | 4 | 5 | #include 6 | 7 | 8 | namespace wotpp { 9 | // Types for obj_t 10 | enum class TYPE: uint8_t { 11 | CHR, 12 | NUM, 13 | PTR 14 | }; 15 | 16 | 17 | struct __attribute__ ((packed)) obj_t { 18 | TYPE type; 19 | union { 20 | int8_t chr; 21 | int32_t num; 22 | void* ptr; 23 | }; 24 | }; 25 | } 26 | 27 | 28 | #endif -------------------------------------------------------------------------------- /wotpp/stack/stack.cpp: -------------------------------------------------------------------------------- 1 | #ifndef WOTPP_STACK_CPP 2 | #define WOTPP_STACK_CPP 3 | 4 | 5 | #include "stack.h" 6 | 7 | 8 | namespace wotpp { 9 | stack::stack(int s): 10 | top(0), 11 | size(s) 12 | { 13 | stk.resize(size); 14 | } 15 | 16 | 17 | int stack::push(const wotpp::obj_t& o) { 18 | stk[top++] = o; 19 | return top; 20 | } 21 | 22 | 23 | wotpp::obj_t stack::pop() { 24 | return stk[--top]; 25 | } 26 | 27 | 28 | std::vector stack::pop(int n) { 29 | std::vector popped(n); 30 | 31 | 32 | for (int i = 0; i < n; ++i) 33 | popped[i] = pop(); 34 | 35 | return popped; 36 | } 37 | 38 | 39 | const wotpp::obj_t& stack::peek(int i) { 40 | return stk[i]; 41 | } 42 | 43 | 44 | const wotpp::obj_t& stack::peek() { 45 | return stk[top - 1]; 46 | } 47 | } 48 | 49 | 50 | #endif -------------------------------------------------------------------------------- /wotpp/stack/stack.h: -------------------------------------------------------------------------------- 1 | #ifndef WOTPP_STACK_H 2 | #define WOTPP_STACK_H 3 | 4 | 5 | #include 6 | #include "../object/object.h" 7 | 8 | 9 | namespace wotpp { 10 | struct stack { 11 | int top, size; 12 | std::vector stk; 13 | 14 | 15 | stack(int s); 16 | 17 | 18 | int push(const wotpp::obj_t& o); 19 | wotpp::obj_t pop(); 20 | std::vector pop(int n); 21 | const wotpp::obj_t& peek(int i); 22 | const wotpp::obj_t& peek(); 23 | }; 24 | } 25 | 26 | 27 | #endif -------------------------------------------------------------------------------- /wotpp/stack_group/stack_group.cpp: -------------------------------------------------------------------------------- 1 | #ifndef WOTPP_STACK_GROUP_CPP 2 | #define WOTPP_STACK_GROUP_CPP 3 | 4 | 5 | #include "stack_group.h" 6 | 7 | 8 | namespace wotpp { 9 | stack_group::stack_group(const std::vector& stacks_): 10 | stacks(stacks_) 11 | { 12 | 13 | } 14 | 15 | wotpp::stack& stack_group::operator[](int index) { 16 | return stacks[index]; 17 | } 18 | } 19 | 20 | 21 | #endif -------------------------------------------------------------------------------- /wotpp/stack_group/stack_group.h: -------------------------------------------------------------------------------- 1 | #ifndef WOTPP_STACK_GROUP_H 2 | #define WOTPP_STACK_GROUP_H 3 | 4 | 5 | #include 6 | #include "../stack/stack.h" 7 | 8 | 9 | namespace wotpp { 10 | struct stack_group { 11 | std::vector stacks; 12 | 13 | 14 | stack_group(const std::vector& stacks_); 15 | 16 | 17 | wotpp::stack& operator[](int index); 18 | }; 19 | } 20 | 21 | 22 | #endif -------------------------------------------------------------------------------- /wotpp/utils.h: -------------------------------------------------------------------------------- 1 | #ifndef WOTPP_UTILS_H 2 | #define WOTPP_UTILS_H 3 | 4 | 5 | #include "utils/read_file.h" 6 | #include "utils/types.h" 7 | 8 | 9 | #endif -------------------------------------------------------------------------------- /wotpp/utils/read_file.h: -------------------------------------------------------------------------------- 1 | #ifndef WOTPP_READ_FILE_H 2 | #define WOTPP_READ_FILE_H 3 | 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include "types.h" 10 | 11 | 12 | namespace wotpp { 13 | std::tuple read_file(const std::string& fname) { 14 | std::ifstream is(fname, std::ios::binary | std::ios::ate); 15 | 16 | // If file does not exist, return empty string and error. 17 | if (!is.is_open()) { 18 | return std::make_tuple(false, ""); 19 | } 20 | 21 | // Create and fill buffer. 22 | size_t size = is.tellg(); 23 | std::string str(size, '\0'); 24 | is.seekg(0); 25 | is.read(&str[0], size); 26 | 27 | // Cleanup. 28 | is.close(); 29 | 30 | // Return string and success. 31 | return std::make_tuple(true, str); 32 | } 33 | } 34 | 35 | 36 | #endif -------------------------------------------------------------------------------- /wotpp/utils/types.h: -------------------------------------------------------------------------------- 1 | #ifndef WOTPP_TYPES_H 2 | #define WOTPP_TYPES_H 3 | 4 | 5 | #include 6 | #include 7 | #include 8 | #include "../stack_group/stack_group.h" 9 | 10 | 11 | namespace wotpp { 12 | using ptr = uint8_t*; 13 | using instr_ptr = wotpp::ptr; 14 | 15 | using heap = std::vector; 16 | 17 | using op = void(*)( 18 | wotpp::instr_ptr&, 19 | wotpp::instr_ptr, 20 | wotpp::stack_group&, 21 | wotpp::heap&, 22 | bool& 23 | ); 24 | using op_group = std::array; 25 | 26 | using code = std::string; 27 | } 28 | 29 | 30 | #endif -------------------------------------------------------------------------------- /wotpp/vm/vm.cpp: -------------------------------------------------------------------------------- 1 | #ifndef WOTPP_VM_CPP 2 | #define WOTPP_VM_CPP 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | 9 | #include "vm.h" 10 | 11 | 12 | namespace wotpp { 13 | void execute( 14 | wotpp::stack_group& stacks, 15 | wotpp::heap& heap, 16 | const wotpp::op_group& operations, 17 | wotpp::code& code 18 | ) { 19 | bool running = true; 20 | 21 | // Set instruction pointer to the start of the code. 22 | wotpp::instr_ptr ip = (uint8_t*)&code[0]; 23 | wotpp::instr_ptr initial_d = (uint8_t*)&code[0]; 24 | 25 | do { 26 | //std::cerr << "\nOPCODE: " << (int)*ip << std::endl; 27 | operations[*ip](ip, initial_d, stacks, heap, running); 28 | //std::this_thread::sleep_for(std::chrono::milliseconds(200)); 29 | } while (running); 30 | } 31 | } 32 | 33 | 34 | #endif -------------------------------------------------------------------------------- /wotpp/vm/vm.h: -------------------------------------------------------------------------------- 1 | #ifndef WOTPP_VM_H 2 | #define WOTPP_VM_H 3 | 4 | 5 | #include "../utils/types.h" 6 | 7 | 8 | namespace wotpp { 9 | void execute( 10 | wotpp::stack_group& stacks, 11 | wotpp::heap& heap, 12 | const wotpp::op_group& operations, 13 | wotpp::code& code 14 | ); 15 | } 16 | 17 | 18 | #endif --------------------------------------------------------------------------------