├── LICENSE ├── README.md ├── bt_lexer.cpp ├── bt_lexer.h ├── bt_parser.cpp ├── bt_parser.h ├── btvm ├── btvm.cpp ├── btvm.h ├── btvm_types.cpp ├── btvm_types.h ├── btvmio.cpp ├── btvmio.h ├── format │ └── btentry.h └── vm │ ├── ast.cpp │ ├── ast.h │ ├── vm.cpp │ ├── vm.h │ ├── vm_functions.cpp │ ├── vm_functions.h │ ├── vmvalue.cpp │ └── vmvalue.h ├── generator ├── Makefile ├── bt_lexer.h ├── bt_lexer.re └── bt_parser.y └── tests └── BTVMTest.bt /LICENSE: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | Preamble 9 | 10 | The GNU General Public License is a free, copyleft license for 11 | software and other kinds of works. 12 | 13 | The licenses for most software and other practical works are designed 14 | to take away your freedom to share and change the works. By contrast, 15 | the GNU General Public License is intended to guarantee your freedom to 16 | share and change all versions of a program--to make sure it remains free 17 | software for all its users. We, the Free Software Foundation, use the 18 | GNU General Public License for most of our software; it applies also to 19 | any other work released this way by its authors. You can apply it to 20 | your programs, too. 21 | 22 | When we speak of free software, we are referring to freedom, not 23 | price. Our General Public Licenses are designed to make sure that you 24 | have the freedom to distribute copies of free software (and charge for 25 | them if you wish), that you receive source code or can get it if you 26 | want it, that you can change the software or use pieces of it in new 27 | free programs, and that you know you can do these things. 28 | 29 | To protect your rights, we need to prevent others from denying you 30 | these rights or asking you to surrender the rights. Therefore, you have 31 | certain responsibilities if you distribute copies of the software, or if 32 | you modify it: responsibilities to respect the freedom of others. 33 | 34 | For example, if you distribute copies of such a program, whether 35 | gratis or for a fee, you must pass on to the recipients the same 36 | freedoms that you received. You must make sure that they, too, receive 37 | or can get the source code. And you must show them these terms so they 38 | know their rights. 39 | 40 | Developers that use the GNU GPL protect your rights with two steps: 41 | (1) assert copyright on the software, and (2) offer you this License 42 | giving you legal permission to copy, distribute and/or modify it. 43 | 44 | For the developers' and authors' protection, the GPL clearly explains 45 | that there is no warranty for this free software. For both users' and 46 | authors' sake, the GPL requires that modified versions be marked as 47 | changed, so that their problems will not be attributed erroneously to 48 | authors of previous versions. 49 | 50 | Some devices are designed to deny users access to install or run 51 | modified versions of the software inside them, although the manufacturer 52 | can do so. This is fundamentally incompatible with the aim of 53 | protecting users' freedom to change the software. The systematic 54 | pattern of such abuse occurs in the area of products for individuals to 55 | use, which is precisely where it is most unacceptable. Therefore, we 56 | have designed this version of the GPL to prohibit the practice for those 57 | products. If such problems arise substantially in other domains, we 58 | stand ready to extend this provision to those domains in future versions 59 | of the GPL, as needed to protect the freedom of users. 60 | 61 | Finally, every program is threatened constantly by software patents. 62 | States should not allow patents to restrict development and use of 63 | software on general-purpose computers, but in those that do, we wish to 64 | avoid the special danger that patents applied to a free program could 65 | make it effectively proprietary. To prevent this, the GPL assures that 66 | patents cannot be used to render the program non-free. 67 | 68 | The precise terms and conditions for copying, distribution and 69 | modification follow. 70 | 71 | TERMS AND CONDITIONS 72 | 73 | 0. Definitions. 74 | 75 | "This License" refers to version 3 of the GNU General Public License. 76 | 77 | "Copyright" also means copyright-like laws that apply to other kinds of 78 | works, such as semiconductor masks. 79 | 80 | "The Program" refers to any copyrightable work licensed under this 81 | License. Each licensee is addressed as "you". "Licensees" and 82 | "recipients" may be individuals or organizations. 83 | 84 | To "modify" a work means to copy from or adapt all or part of the work 85 | in a fashion requiring copyright permission, other than the making of an 86 | exact copy. The resulting work is called a "modified version" of the 87 | earlier work or a work "based on" the earlier work. 88 | 89 | A "covered work" means either the unmodified Program or a work based 90 | on the Program. 91 | 92 | To "propagate" a work means to do anything with it that, without 93 | permission, would make you directly or secondarily liable for 94 | infringement under applicable copyright law, except executing it on a 95 | computer or modifying a private copy. Propagation includes copying, 96 | distribution (with or without modification), making available to the 97 | public, and in some countries other activities as well. 98 | 99 | To "convey" a work means any kind of propagation that enables other 100 | parties to make or receive copies. Mere interaction with a user through 101 | a computer network, with no transfer of a copy, is not conveying. 102 | 103 | An interactive user interface displays "Appropriate Legal Notices" 104 | to the extent that it includes a convenient and prominently visible 105 | feature that (1) displays an appropriate copyright notice, and (2) 106 | tells the user that there is no warranty for the work (except to the 107 | extent that warranties are provided), that licensees may convey the 108 | work under this License, and how to view a copy of this License. If 109 | the interface presents a list of user commands or options, such as a 110 | menu, a prominent item in the list meets this criterion. 111 | 112 | 1. Source Code. 113 | 114 | The "source code" for a work means the preferred form of the work 115 | for making modifications to it. "Object code" means any non-source 116 | form of a work. 117 | 118 | A "Standard Interface" means an interface that either is an official 119 | standard defined by a recognized standards body, or, in the case of 120 | interfaces specified for a particular programming language, one that 121 | is widely used among developers working in that language. 122 | 123 | The "System Libraries" of an executable work include anything, other 124 | than the work as a whole, that (a) is included in the normal form of 125 | packaging a Major Component, but which is not part of that Major 126 | Component, and (b) serves only to enable use of the work with that 127 | Major Component, or to implement a Standard Interface for which an 128 | implementation is available to the public in source code form. A 129 | "Major Component", in this context, means a major essential component 130 | (kernel, window system, and so on) of the specific operating system 131 | (if any) on which the executable work runs, or a compiler used to 132 | produce the work, or an object code interpreter used to run it. 133 | 134 | The "Corresponding Source" for a work in object code form means all 135 | the source code needed to generate, install, and (for an executable 136 | work) run the object code and to modify the work, including scripts to 137 | control those activities. However, it does not include the work's 138 | System Libraries, or general-purpose tools or generally available free 139 | programs which are used unmodified in performing those activities but 140 | which are not part of the work. For example, Corresponding Source 141 | includes interface definition files associated with source files for 142 | the work, and the source code for shared libraries and dynamically 143 | linked subprograms that the work is specifically designed to require, 144 | such as by intimate data communication or control flow between those 145 | subprograms and other parts of the work. 146 | 147 | The Corresponding Source need not include anything that users 148 | can regenerate automatically from other parts of the Corresponding 149 | Source. 150 | 151 | The Corresponding Source for a work in source code form is that 152 | same work. 153 | 154 | 2. Basic Permissions. 155 | 156 | All rights granted under this License are granted for the term of 157 | copyright on the Program, and are irrevocable provided the stated 158 | conditions are met. This License explicitly affirms your unlimited 159 | permission to run the unmodified Program. The output from running a 160 | covered work is covered by this License only if the output, given its 161 | content, constitutes a covered work. This License acknowledges your 162 | rights of fair use or other equivalent, as provided by copyright law. 163 | 164 | You may make, run and propagate covered works that you do not 165 | convey, without conditions so long as your license otherwise remains 166 | in force. You may convey covered works to others for the sole purpose 167 | of having them make modifications exclusively for you, or provide you 168 | with facilities for running those works, provided that you comply with 169 | the terms of this License in conveying all material for which you do 170 | not control copyright. Those thus making or running the covered works 171 | for you must do so exclusively on your behalf, under your direction 172 | and control, on terms that prohibit them from making any copies of 173 | your copyrighted material outside their relationship with you. 174 | 175 | Conveying under any other circumstances is permitted solely under 176 | the conditions stated below. Sublicensing is not allowed; section 10 177 | makes it unnecessary. 178 | 179 | 3. Protecting Users' Legal Rights From Anti-Circumvention Law. 180 | 181 | No covered work shall be deemed part of an effective technological 182 | measure under any applicable law fulfilling obligations under article 183 | 11 of the WIPO copyright treaty adopted on 20 December 1996, or 184 | similar laws prohibiting or restricting circumvention of such 185 | measures. 186 | 187 | When you convey a covered work, you waive any legal power to forbid 188 | circumvention of technological measures to the extent such circumvention 189 | is effected by exercising rights under this License with respect to 190 | the covered work, and you disclaim any intention to limit operation or 191 | modification of the work as a means of enforcing, against the work's 192 | users, your or third parties' legal rights to forbid circumvention of 193 | technological measures. 194 | 195 | 4. Conveying Verbatim Copies. 196 | 197 | You may convey verbatim copies of the Program's source code as you 198 | receive it, in any medium, provided that you conspicuously and 199 | appropriately publish on each copy an appropriate copyright notice; 200 | keep intact all notices stating that this License and any 201 | non-permissive terms added in accord with section 7 apply to the code; 202 | keep intact all notices of the absence of any warranty; and give all 203 | recipients a copy of this License along with the Program. 204 | 205 | You may charge any price or no price for each copy that you convey, 206 | and you may offer support or warranty protection for a fee. 207 | 208 | 5. Conveying Modified Source Versions. 209 | 210 | You may convey a work based on the Program, or the modifications to 211 | produce it from the Program, in the form of source code under the 212 | terms of section 4, provided that you also meet all of these conditions: 213 | 214 | a) The work must carry prominent notices stating that you modified 215 | it, and giving a relevant date. 216 | 217 | b) The work must carry prominent notices stating that it is 218 | released under this License and any conditions added under section 219 | 7. This requirement modifies the requirement in section 4 to 220 | "keep intact all notices". 221 | 222 | c) You must license the entire work, as a whole, under this 223 | License to anyone who comes into possession of a copy. This 224 | License will therefore apply, along with any applicable section 7 225 | additional terms, to the whole of the work, and all its parts, 226 | regardless of how they are packaged. This License gives no 227 | permission to license the work in any other way, but it does not 228 | invalidate such permission if you have separately received it. 229 | 230 | d) If the work has interactive user interfaces, each must display 231 | Appropriate Legal Notices; however, if the Program has interactive 232 | interfaces that do not display Appropriate Legal Notices, your 233 | work need not make them do so. 234 | 235 | A compilation of a covered work with other separate and independent 236 | works, which are not by their nature extensions of the covered work, 237 | and which are not combined with it such as to form a larger program, 238 | in or on a volume of a storage or distribution medium, is called an 239 | "aggregate" if the compilation and its resulting copyright are not 240 | used to limit the access or legal rights of the compilation's users 241 | beyond what the individual works permit. Inclusion of a covered work 242 | in an aggregate does not cause this License to apply to the other 243 | parts of the aggregate. 244 | 245 | 6. Conveying Non-Source Forms. 246 | 247 | You may convey a covered work in object code form under the terms 248 | of sections 4 and 5, provided that you also convey the 249 | machine-readable Corresponding Source under the terms of this License, 250 | in one of these ways: 251 | 252 | a) Convey the object code in, or embodied in, a physical product 253 | (including a physical distribution medium), accompanied by the 254 | Corresponding Source fixed on a durable physical medium 255 | customarily used for software interchange. 256 | 257 | b) Convey the object code in, or embodied in, a physical product 258 | (including a physical distribution medium), accompanied by a 259 | written offer, valid for at least three years and valid for as 260 | long as you offer spare parts or customer support for that product 261 | model, to give anyone who possesses the object code either (1) a 262 | copy of the Corresponding Source for all the software in the 263 | product that is covered by this License, on a durable physical 264 | medium customarily used for software interchange, for a price no 265 | more than your reasonable cost of physically performing this 266 | conveying of source, or (2) access to copy the 267 | Corresponding Source from a network server at no charge. 268 | 269 | c) Convey individual copies of the object code with a copy of the 270 | written offer to provide the Corresponding Source. This 271 | alternative is allowed only occasionally and noncommercially, and 272 | only if you received the object code with such an offer, in accord 273 | with subsection 6b. 274 | 275 | d) Convey the object code by offering access from a designated 276 | place (gratis or for a charge), and offer equivalent access to the 277 | Corresponding Source in the same way through the same place at no 278 | further charge. You need not require recipients to copy the 279 | Corresponding Source along with the object code. If the place to 280 | copy the object code is a network server, the Corresponding Source 281 | may be on a different server (operated by you or a third party) 282 | that supports equivalent copying facilities, provided you maintain 283 | clear directions next to the object code saying where to find the 284 | Corresponding Source. Regardless of what server hosts the 285 | Corresponding Source, you remain obligated to ensure that it is 286 | available for as long as needed to satisfy these requirements. 287 | 288 | e) Convey the object code using peer-to-peer transmission, provided 289 | you inform other peers where the object code and Corresponding 290 | Source of the work are being offered to the general public at no 291 | charge under subsection 6d. 292 | 293 | A separable portion of the object code, whose source code is excluded 294 | from the Corresponding Source as a System Library, need not be 295 | included in conveying the object code work. 296 | 297 | A "User Product" is either (1) a "consumer product", which means any 298 | tangible personal property which is normally used for personal, family, 299 | or household purposes, or (2) anything designed or sold for incorporation 300 | into a dwelling. In determining whether a product is a consumer product, 301 | doubtful cases shall be resolved in favor of coverage. For a particular 302 | product received by a particular user, "normally used" refers to a 303 | typical or common use of that class of product, regardless of the status 304 | of the particular user or of the way in which the particular user 305 | actually uses, or expects or is expected to use, the product. A product 306 | is a consumer product regardless of whether the product has substantial 307 | commercial, industrial or non-consumer uses, unless such uses represent 308 | the only significant mode of use of the product. 309 | 310 | "Installation Information" for a User Product means any methods, 311 | procedures, authorization keys, or other information required to install 312 | and execute modified versions of a covered work in that User Product from 313 | a modified version of its Corresponding Source. The information must 314 | suffice to ensure that the continued functioning of the modified object 315 | code is in no case prevented or interfered with solely because 316 | modification has been made. 317 | 318 | If you convey an object code work under this section in, or with, or 319 | specifically for use in, a User Product, and the conveying occurs as 320 | part of a transaction in which the right of possession and use of the 321 | User Product is transferred to the recipient in perpetuity or for a 322 | fixed term (regardless of how the transaction is characterized), the 323 | Corresponding Source conveyed under this section must be accompanied 324 | by the Installation Information. But this requirement does not apply 325 | if neither you nor any third party retains the ability to install 326 | modified object code on the User Product (for example, the work has 327 | been installed in ROM). 328 | 329 | The requirement to provide Installation Information does not include a 330 | requirement to continue to provide support service, warranty, or updates 331 | for a work that has been modified or installed by the recipient, or for 332 | the User Product in which it has been modified or installed. Access to a 333 | network may be denied when the modification itself materially and 334 | adversely affects the operation of the network or violates the rules and 335 | protocols for communication across the network. 336 | 337 | Corresponding Source conveyed, and Installation Information provided, 338 | in accord with this section must be in a format that is publicly 339 | documented (and with an implementation available to the public in 340 | source code form), and must require no special password or key for 341 | unpacking, reading or copying. 342 | 343 | 7. Additional Terms. 344 | 345 | "Additional permissions" are terms that supplement the terms of this 346 | License by making exceptions from one or more of its conditions. 347 | Additional permissions that are applicable to the entire Program shall 348 | be treated as though they were included in this License, to the extent 349 | that they are valid under applicable law. If additional permissions 350 | apply only to part of the Program, that part may be used separately 351 | under those permissions, but the entire Program remains governed by 352 | this License without regard to the additional permissions. 353 | 354 | When you convey a copy of a covered work, you may at your option 355 | remove any additional permissions from that copy, or from any part of 356 | it. (Additional permissions may be written to require their own 357 | removal in certain cases when you modify the work.) You may place 358 | additional permissions on material, added by you to a covered work, 359 | for which you have or can give appropriate copyright permission. 360 | 361 | Notwithstanding any other provision of this License, for material you 362 | add to a covered work, you may (if authorized by the copyright holders of 363 | that material) supplement the terms of this License with terms: 364 | 365 | a) Disclaiming warranty or limiting liability differently from the 366 | terms of sections 15 and 16 of this License; or 367 | 368 | b) Requiring preservation of specified reasonable legal notices or 369 | author attributions in that material or in the Appropriate Legal 370 | Notices displayed by works containing it; or 371 | 372 | c) Prohibiting misrepresentation of the origin of that material, or 373 | requiring that modified versions of such material be marked in 374 | reasonable ways as different from the original version; or 375 | 376 | d) Limiting the use for publicity purposes of names of licensors or 377 | authors of the material; or 378 | 379 | e) Declining to grant rights under trademark law for use of some 380 | trade names, trademarks, or service marks; or 381 | 382 | f) Requiring indemnification of licensors and authors of that 383 | material by anyone who conveys the material (or modified versions of 384 | it) with contractual assumptions of liability to the recipient, for 385 | any liability that these contractual assumptions directly impose on 386 | those licensors and authors. 387 | 388 | All other non-permissive additional terms are considered "further 389 | restrictions" within the meaning of section 10. If the Program as you 390 | received it, or any part of it, contains a notice stating that it is 391 | governed by this License along with a term that is a further 392 | restriction, you may remove that term. If a license document contains 393 | a further restriction but permits relicensing or conveying under this 394 | License, you may add to a covered work material governed by the terms 395 | of that license document, provided that the further restriction does 396 | not survive such relicensing or conveying. 397 | 398 | If you add terms to a covered work in accord with this section, you 399 | must place, in the relevant source files, a statement of the 400 | additional terms that apply to those files, or a notice indicating 401 | where to find the applicable terms. 402 | 403 | Additional terms, permissive or non-permissive, may be stated in the 404 | form of a separately written license, or stated as exceptions; 405 | the above requirements apply either way. 406 | 407 | 8. Termination. 408 | 409 | You may not propagate or modify a covered work except as expressly 410 | provided under this License. Any attempt otherwise to propagate or 411 | modify it is void, and will automatically terminate your rights under 412 | this License (including any patent licenses granted under the third 413 | paragraph of section 11). 414 | 415 | However, if you cease all violation of this License, then your 416 | license from a particular copyright holder is reinstated (a) 417 | provisionally, unless and until the copyright holder explicitly and 418 | finally terminates your license, and (b) permanently, if the copyright 419 | holder fails to notify you of the violation by some reasonable means 420 | prior to 60 days after the cessation. 421 | 422 | Moreover, your license from a particular copyright holder is 423 | reinstated permanently if the copyright holder notifies you of the 424 | violation by some reasonable means, this is the first time you have 425 | received notice of violation of this License (for any work) from that 426 | copyright holder, and you cure the violation prior to 30 days after 427 | your receipt of the notice. 428 | 429 | Termination of your rights under this section does not terminate the 430 | licenses of parties who have received copies or rights from you under 431 | this License. If your rights have been terminated and not permanently 432 | reinstated, you do not qualify to receive new licenses for the same 433 | material under section 10. 434 | 435 | 9. Acceptance Not Required for Having Copies. 436 | 437 | You are not required to accept this License in order to receive or 438 | run a copy of the Program. Ancillary propagation of a covered work 439 | occurring solely as a consequence of using peer-to-peer transmission 440 | to receive a copy likewise does not require acceptance. However, 441 | nothing other than this License grants you permission to propagate or 442 | modify any covered work. These actions infringe copyright if you do 443 | not accept this License. Therefore, by modifying or propagating a 444 | covered work, you indicate your acceptance of this License to do so. 445 | 446 | 10. Automatic Licensing of Downstream Recipients. 447 | 448 | Each time you convey a covered work, the recipient automatically 449 | receives a license from the original licensors, to run, modify and 450 | propagate that work, subject to this License. You are not responsible 451 | for enforcing compliance by third parties with this License. 452 | 453 | An "entity transaction" is a transaction transferring control of an 454 | organization, or substantially all assets of one, or subdividing an 455 | organization, or merging organizations. If propagation of a covered 456 | work results from an entity transaction, each party to that 457 | transaction who receives a copy of the work also receives whatever 458 | licenses to the work the party's predecessor in interest had or could 459 | give under the previous paragraph, plus a right to possession of the 460 | Corresponding Source of the work from the predecessor in interest, if 461 | the predecessor has it or can get it with reasonable efforts. 462 | 463 | You may not impose any further restrictions on the exercise of the 464 | rights granted or affirmed under this License. For example, you may 465 | not impose a license fee, royalty, or other charge for exercise of 466 | rights granted under this License, and you may not initiate litigation 467 | (including a cross-claim or counterclaim in a lawsuit) alleging that 468 | any patent claim is infringed by making, using, selling, offering for 469 | sale, or importing the Program or any portion of it. 470 | 471 | 11. Patents. 472 | 473 | A "contributor" is a copyright holder who authorizes use under this 474 | License of the Program or a work on which the Program is based. The 475 | work thus licensed is called the contributor's "contributor version". 476 | 477 | A contributor's "essential patent claims" are all patent claims 478 | owned or controlled by the contributor, whether already acquired or 479 | hereafter acquired, that would be infringed by some manner, permitted 480 | by this License, of making, using, or selling its contributor version, 481 | but do not include claims that would be infringed only as a 482 | consequence of further modification of the contributor version. For 483 | purposes of this definition, "control" includes the right to grant 484 | patent sublicenses in a manner consistent with the requirements of 485 | this License. 486 | 487 | Each contributor grants you a non-exclusive, worldwide, royalty-free 488 | patent license under the contributor's essential patent claims, to 489 | make, use, sell, offer for sale, import and otherwise run, modify and 490 | propagate the contents of its contributor version. 491 | 492 | In the following three paragraphs, a "patent license" is any express 493 | agreement or commitment, however denominated, not to enforce a patent 494 | (such as an express permission to practice a patent or covenant not to 495 | sue for patent infringement). To "grant" such a patent license to a 496 | party means to make such an agreement or commitment not to enforce a 497 | patent against the party. 498 | 499 | If you convey a covered work, knowingly relying on a patent license, 500 | and the Corresponding Source of the work is not available for anyone 501 | to copy, free of charge and under the terms of this License, through a 502 | publicly available network server or other readily accessible means, 503 | then you must either (1) cause the Corresponding Source to be so 504 | available, or (2) arrange to deprive yourself of the benefit of the 505 | patent license for this particular work, or (3) arrange, in a manner 506 | consistent with the requirements of this License, to extend the patent 507 | license to downstream recipients. "Knowingly relying" means you have 508 | actual knowledge that, but for the patent license, your conveying the 509 | covered work in a country, or your recipient's use of the covered work 510 | in a country, would infringe one or more identifiable patents in that 511 | country that you have reason to believe are valid. 512 | 513 | If, pursuant to or in connection with a single transaction or 514 | arrangement, you convey, or propagate by procuring conveyance of, a 515 | covered work, and grant a patent license to some of the parties 516 | receiving the covered work authorizing them to use, propagate, modify 517 | or convey a specific copy of the covered work, then the patent license 518 | you grant is automatically extended to all recipients of the covered 519 | work and works based on it. 520 | 521 | A patent license is "discriminatory" if it does not include within 522 | the scope of its coverage, prohibits the exercise of, or is 523 | conditioned on the non-exercise of one or more of the rights that are 524 | specifically granted under this License. You may not convey a covered 525 | work if you are a party to an arrangement with a third party that is 526 | in the business of distributing software, under which you make payment 527 | to the third party based on the extent of your activity of conveying 528 | the work, and under which the third party grants, to any of the 529 | parties who would receive the covered work from you, a discriminatory 530 | patent license (a) in connection with copies of the covered work 531 | conveyed by you (or copies made from those copies), or (b) primarily 532 | for and in connection with specific products or compilations that 533 | contain the covered work, unless you entered into that arrangement, 534 | or that patent license was granted, prior to 28 March 2007. 535 | 536 | Nothing in this License shall be construed as excluding or limiting 537 | any implied license or other defenses to infringement that may 538 | otherwise be available to you under applicable patent law. 539 | 540 | 12. No Surrender of Others' Freedom. 541 | 542 | If conditions are imposed on you (whether by court order, agreement or 543 | otherwise) that contradict the conditions of this License, they do not 544 | excuse you from the conditions of this License. If you cannot convey a 545 | covered work so as to satisfy simultaneously your obligations under this 546 | License and any other pertinent obligations, then as a consequence you may 547 | not convey it at all. For example, if you agree to terms that obligate you 548 | to collect a royalty for further conveying from those to whom you convey 549 | the Program, the only way you could satisfy both those terms and this 550 | License would be to refrain entirely from conveying the Program. 551 | 552 | 13. Use with the GNU Affero General Public License. 553 | 554 | Notwithstanding any other provision of this License, you have 555 | permission to link or combine any covered work with a work licensed 556 | under version 3 of the GNU Affero General Public License into a single 557 | combined work, and to convey the resulting work. The terms of this 558 | License will continue to apply to the part which is the covered work, 559 | but the special requirements of the GNU Affero General Public License, 560 | section 13, concerning interaction through a network will apply to the 561 | combination as such. 562 | 563 | 14. Revised Versions of this License. 564 | 565 | The Free Software Foundation may publish revised and/or new versions of 566 | the GNU General Public License from time to time. Such new versions will 567 | be similar in spirit to the present version, but may differ in detail to 568 | address new problems or concerns. 569 | 570 | Each version is given a distinguishing version number. If the 571 | Program specifies that a certain numbered version of the GNU General 572 | Public License "or any later version" applies to it, you have the 573 | option of following the terms and conditions either of that numbered 574 | version or of any later version published by the Free Software 575 | Foundation. If the Program does not specify a version number of the 576 | GNU General Public License, you may choose any version ever published 577 | by the Free Software Foundation. 578 | 579 | If the Program specifies that a proxy can decide which future 580 | versions of the GNU General Public License can be used, that proxy's 581 | public statement of acceptance of a version permanently authorizes you 582 | to choose that version for the Program. 583 | 584 | Later license versions may give you additional or different 585 | permissions. However, no additional obligations are imposed on any 586 | author or copyright holder as a result of your choosing to follow a 587 | later version. 588 | 589 | 15. Disclaimer of Warranty. 590 | 591 | THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY 592 | APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT 593 | HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY 594 | OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, 595 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 596 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM 597 | IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF 598 | ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 599 | 600 | 16. Limitation of Liability. 601 | 602 | IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 603 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS 604 | THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY 605 | GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE 606 | USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF 607 | DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD 608 | PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), 609 | EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF 610 | SUCH DAMAGES. 611 | 612 | 17. Interpretation of Sections 15 and 16. 613 | 614 | If the disclaimer of warranty and limitation of liability provided 615 | above cannot be given local legal effect according to their terms, 616 | reviewing courts shall apply local law that most closely approximates 617 | an absolute waiver of all civil liability in connection with the 618 | Program, unless a warranty or assumption of liability accompanies a 619 | copy of the Program in return for a fee. 620 | 621 | END OF TERMS AND CONDITIONS 622 | 623 | How to Apply These Terms to Your New Programs 624 | 625 | If you develop a new program, and you want it to be of the greatest 626 | possible use to the public, the best way to achieve this is to make it 627 | free software which everyone can redistribute and change under these terms. 628 | 629 | To do so, attach the following notices to the program. It is safest 630 | to attach them to the start of each source file to most effectively 631 | state the exclusion of warranty; and each file should have at least 632 | the "copyright" line and a pointer to where the full notice is found. 633 | 634 | {one line to give the program's name and a brief idea of what it does.} 635 | Copyright (C) {year} {name of author} 636 | 637 | This program is free software: you can redistribute it and/or modify 638 | it under the terms of the GNU General Public License as published by 639 | the Free Software Foundation, either version 3 of the License, or 640 | (at your option) any later version. 641 | 642 | This program is distributed in the hope that it will be useful, 643 | but WITHOUT ANY WARRANTY; without even the implied warranty of 644 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 645 | GNU General Public License for more details. 646 | 647 | You should have received a copy of the GNU General Public License 648 | along with this program. If not, see . 649 | 650 | Also add information on how to contact you by electronic and paper mail. 651 | 652 | If the program does terminal interaction, make it output a short 653 | notice like this when it starts in an interactive mode: 654 | 655 | {project} Copyright (C) {year} {fullname} 656 | This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 657 | This is free software, and you are welcome to redistribute it 658 | under certain conditions; type `show c' for details. 659 | 660 | The hypothetical commands `show w' and `show c' should show the appropriate 661 | parts of the General Public License. Of course, your program's commands 662 | might be different; for a GUI interface, you would use an "about box". 663 | 664 | You should also get your employer (if you work as a programmer) or school, 665 | if any, to sign a "copyright disclaimer" for the program, if necessary. 666 | For more information on this, and how to apply and follow the GNU GPL, see 667 | . 668 | 669 | The GNU General Public License does not permit incorporating your program 670 | into proprietary programs. If your program is a subroutine library, you 671 | may consider it more useful to permit linking proprietary applications with 672 | the library. If this is what you want to do, use the GNU Lesser General 673 | Public License instead of this License. But first, please read 674 | . 675 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # BTVM 2 | C++11 implementation of 010 Editor's template language 3 | 4 | ## Status 5 | BTVM is in early state, lexing and parsing works on some scripts: 6 | * BMP Format 7 | * WAV Format 8 | * ZIP Format 9 | * EXE Format 10 | 11 | A detailed wiki page about BTVM's status will be available soon. 12 | 13 | ## Build 14 | If order to autogenerate the Lexer (bt_lexer.\*) and Parser (bt_parser.\*), it's sufficient to run "make" inside "generator" folder (lemon and re2c needs to be installed): 15 | 16 | ``` 17 | cd generator 18 | make 19 | cd .. 20 | ``` 21 | 22 | ## Usage 23 | 24 | ``` 25 | #include 26 | #include "btvm/btvm.h" 27 | #include "your_custom_io_class.h" 28 | 29 | using namespace std; 30 | 31 | // Prints file structure to console 32 | void printElements(const BTEntryList& entries, const std::string& prefix) 33 | { 34 | for(auto it = entries.begin(); it != entries.end(); it++) 35 | { 36 | cout << prefix << (*it)->name << " at offset " << (*it)->location.offset << ", size " << (*it)->location.size << endl; 37 | printElements((*it)->children, prefix + " "); 38 | } 39 | 40 | if(!entries.empty()) 41 | cout << endl; 42 | } 43 | 44 | int main() 45 | { 46 | BTVM btvm(new YourCustomIOClass("myfile.bin")); 47 | btvm.dump("ast.xml"); // Dumps AST to file 48 | btvm.execute("BMPFormat.bt"); 49 | 50 | BTEntryList btformat = btvm.format(); // Get format 51 | printElements(btformat, std::string()); 52 | 53 | return 0; 54 | } 55 | 56 | ``` 57 | 58 | ## License 59 | BTVM is released under GPL3 License 60 | -------------------------------------------------------------------------------- /bt_lexer.h: -------------------------------------------------------------------------------- 1 | #ifndef BT_LEXER_H 2 | #define BT_LEXER_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | using namespace std; 10 | 11 | class BTLexer 12 | { 13 | public: 14 | struct Token { int type; unsigned int line; std::string value; }; 15 | 16 | public: 17 | BTLexer(const char* s); 18 | list lex(); 19 | 20 | private: 21 | string getString(const char* start, const char* end) const; 22 | 23 | private: 24 | const char* _cursor; 25 | const char* _start; 26 | const char* _marker; 27 | }; 28 | 29 | #endif // FLINI_LEXER_H 30 | -------------------------------------------------------------------------------- /bt_parser.h: -------------------------------------------------------------------------------- 1 | #define BTT_O_ROUND 1 2 | #define BTT_C_ROUND 2 3 | #define BTT_COMMA 3 4 | #define BTT_VOID 4 5 | #define BTT_BIN_AND 5 6 | #define BTT_TYPEDEF 6 7 | #define BTT_SEMICOLON 7 8 | #define BTT_STRUCT 8 9 | #define BTT_O_CURLY 9 10 | #define BTT_C_CURLY 10 11 | #define BTT_UNION 11 12 | #define BTT_ENUM 12 13 | #define BTT_LT 13 14 | #define BTT_GT 14 15 | #define BTT_CONST 15 16 | #define BTT_LOCAL 16 17 | #define BTT_ASSIGN 17 18 | #define BTT_COLON 18 19 | #define BTT_O_SQUARE 19 20 | #define BTT_C_SQUARE 20 21 | #define BTT_IDENTIFIER 21 22 | #define BTT_BOOL 22 23 | #define BTT_UNSIGNED 23 24 | #define BTT_SIGNED 24 25 | #define BTT_WSTRING 25 26 | #define BTT_STRING 26 27 | #define BTT_CHAR 27 28 | #define BTT_WCHAR 28 29 | #define BTT_BYTE 29 30 | #define BTT_TIME 30 31 | #define BTT_DOSDATE 31 32 | #define BTT_DOSTIME 32 33 | #define BTT_OLETIME 33 34 | #define BTT_FILETIME 34 35 | #define BTT_UCHAR 35 36 | #define BTT_UBYTE 36 37 | #define BTT_SHORT 37 38 | #define BTT_USHORT 38 39 | #define BTT_INT32 39 40 | #define BTT_UINT32 40 41 | #define BTT_INT64 41 42 | #define BTT_UINT64 42 43 | #define BTT_HFLOAT 43 44 | #define BTT_FLOAT 44 45 | #define BTT_DOUBLE 45 46 | #define BTT_IF 46 47 | #define BTT_ELSE 47 48 | #define BTT_WHILE 48 49 | #define BTT_FOR 49 50 | #define BTT_DO 50 51 | #define BTT_SWITCH 51 52 | #define BTT_BREAK 52 53 | #define BTT_CONTINUE 53 54 | #define BTT_RETURN 54 55 | #define BTT_CASE 55 56 | #define BTT_DEFAULT 56 57 | #define BTT_ADD_ASSIGN 57 58 | #define BTT_SUB_ASSIGN 58 59 | #define BTT_MUL_ASSIGN 59 60 | #define BTT_DIV_ASSIGN 60 61 | #define BTT_XOR_ASSIGN 61 62 | #define BTT_AND_ASSIGN 62 63 | #define BTT_OR_ASSIGN 63 64 | #define BTT_LS_ASSIGN 64 65 | #define BTT_RS_ASSIGN 65 66 | #define BTT_QUESTION 66 67 | #define BTT_LOG_OR 67 68 | #define BTT_LOG_AND 68 69 | #define BTT_BIN_OR 69 70 | #define BTT_BIN_XOR 70 71 | #define BTT_EQ 71 72 | #define BTT_NE 72 73 | #define BTT_LE 73 74 | #define BTT_GE 74 75 | #define BTT_LSL 75 76 | #define BTT_LSR 76 77 | #define BTT_ADD 77 78 | #define BTT_SUB 78 79 | #define BTT_MUL 79 80 | #define BTT_DIV 80 81 | #define BTT_MOD 81 82 | #define BTT_LOG_NOT 82 83 | #define BTT_BIN_NOT 83 84 | #define BTT_INC 84 85 | #define BTT_DEC 85 86 | #define BTT_SIZEOF 86 87 | #define BTT_DOT 87 88 | #define BTT_LITERAL_STRING 88 89 | #define BTT_LITERAL_CHAR 89 90 | #define BTT_LITERAL_OCT 90 91 | #define BTT_LITERAL_DEC 91 92 | #define BTT_LITERAL_HEX 92 93 | #define BTT_LITERAL_REAL 93 94 | #define BTT_TRUE 94 95 | #define BTT_FALSE 95 96 | -------------------------------------------------------------------------------- /btvm/btvm.cpp: -------------------------------------------------------------------------------- 1 | #include "btvm.h" 2 | #include "vm/vm_functions.h" 3 | #include "btvm_types.h" 4 | #include "../bt_lexer.h" 5 | #include 6 | #include 7 | #include 8 | 9 | #define ColorizeFail(s) "\x1b[31m" << s << "\x1b[0m" 10 | #define ColorizeOk(s) "\x1b[32m" << s << "\x1b[0m" 11 | 12 | // Parser interface 13 | void* BTParserAlloc(void* (*mallocproc)(size_t)); 14 | void BTParserFree(void* p, void (*freeproc)(void*)); 15 | void BTParser(void* yyp, int yymajor, BTLexer::Token* yyminor, BTVM* btvm); 16 | 17 | BTVM::BTVM(BTVMIO *btvmio): VM(), _fgcolor(ColorInvalid), _bgcolor(ColorInvalid), _btvmio(btvmio) 18 | { 19 | this->initTypes(); 20 | this->initFunctions(); 21 | this->initColors(); 22 | } 23 | 24 | BTVM::~BTVM() 25 | { 26 | for(auto it = this->_builtin.begin(); it != this->_builtin.end(); it++) 27 | delete *it; 28 | } 29 | 30 | void BTVM::parse(const string &code) 31 | { 32 | VM::parse(code); 33 | 34 | BTLexer lexer(code.c_str()); 35 | std::list tokens = lexer.lex(); 36 | 37 | if(tokens.size() <= 0) 38 | return; 39 | 40 | void* parser = BTParserAlloc(&malloc); 41 | 42 | for(auto it = tokens.begin(); it != tokens.end(); it++) 43 | { 44 | if(this->state == VMState::Error) 45 | break; 46 | 47 | BTParser(parser, it->type, &(*it), this); 48 | } 49 | 50 | BTParser(parser, 0, NULL, this); 51 | BTParserFree(parser, &free); 52 | } 53 | 54 | BTEntryList BTVM::createTemplate() 55 | { 56 | BTEntryList btfmt; 57 | 58 | if(this->state == VMState::NoState) 59 | { 60 | for(auto it = this->allocations.begin(); it != this->allocations.end(); it++) 61 | btfmt.push_back(this->createEntry(*it, NULL)); 62 | } 63 | else 64 | this->allocations.clear(); 65 | 66 | return btfmt; 67 | } 68 | 69 | void BTVM::print(const string &s) 70 | { 71 | cout << s; 72 | } 73 | 74 | void BTVM::readValue(const VMValuePtr& vmvar, uint64_t size, bool seek) 75 | { 76 | if(!seek) 77 | { 78 | IO_NoSeek(this->_btvmio); 79 | this->_btvmio->read(vmvar, size); 80 | return; 81 | } 82 | 83 | this->_btvmio->read(vmvar, size); 84 | } 85 | 86 | void BTVM::entryCreated(const BTEntryPtr &btentry) 87 | { 88 | VMUnused(btentry); 89 | } 90 | 91 | uint64_t BTVM::currentOffset() const 92 | { 93 | return this->_btvmio->offset(); 94 | } 95 | 96 | uint32_t BTVM::color(const string &color) const 97 | { 98 | auto it = this->_colors.find(color); 99 | 100 | if(it == this->_colors.end()) 101 | return ColorInvalid; 102 | 103 | return it->second; 104 | } 105 | 106 | uint32_t BTVM::currentFgColor() const 107 | { 108 | return this->_fgcolor; 109 | } 110 | 111 | uint32_t BTVM::currentBgColor() const 112 | { 113 | 114 | return this->_bgcolor; 115 | } 116 | 117 | BTEntryPtr BTVM::createEntry(const VMValuePtr &vmvalue, const BTEntryPtr& btparent) 118 | { 119 | BTEntryPtr btentry = std::make_shared(vmvalue, this->_btvmio->endianness()); 120 | btentry->location = BTLocation(vmvalue->value_offset, this->sizeOf(vmvalue)); 121 | btentry->parent = btparent; 122 | 123 | if(vmvalue->is_array() || node_is(vmvalue->value_typedef, NStruct)) 124 | { 125 | for(auto it = vmvalue->m_value.begin(); it != vmvalue->m_value.end(); it++) 126 | btentry->children.push_back(this->createEntry(*it, btentry)); 127 | } 128 | 129 | this->entryCreated(btentry); 130 | return btentry; 131 | } 132 | 133 | VMValuePtr BTVM::readScalar(NCall *ncall, uint64_t bits, bool issigned) 134 | { 135 | VMValuePtr pos; 136 | 137 | if(ncall->arguments.size() > 1) 138 | return this->error("Expected 0 or 1 arguments, " + std::to_string(ncall->arguments.size()) + " given"); 139 | 140 | IO_NoSeek(this->_btvmio); 141 | 142 | if(ncall->arguments.size() == 1) 143 | { 144 | pos = this->interpret(ncall->arguments.front()); 145 | 146 | if(!pos->is_scalar()) 147 | return this->typeError(pos, "scalar"); 148 | 149 | this->_btvmio->seek(pos->ui_value); 150 | } 151 | 152 | VMValuePtr vmvalue = VMValue::allocate(bits, issigned, false); 153 | this->_btvmio->read(vmvalue, this->sizeOf(vmvalue)); 154 | return vmvalue; 155 | } 156 | 157 | void BTVM::initTypes() 158 | { 159 | Node* n = BTVMTypes::buildTFindResults(); 160 | this->_builtin.push_back(n); 161 | this->declare(n); 162 | } 163 | 164 | void BTVM::initFunctions() 165 | { 166 | // Interface Functions: https://www.sweetscape.com/010editor/manual/FuncInterface.htm 167 | this->functions["Printf"] = &BTVM::vmPrintf; 168 | this->functions["SetBackColor"] = &BTVM::vmSetBackColor; 169 | this->functions["SetForeColor"] = &BTVM::vmSetForeColor; 170 | this->functions["Warning"] = &BTVM::vmWarning; 171 | 172 | // I/O Functions: https://www.sweetscape.com/010editor/manual/FuncIO.htm 173 | this->functions["FEof"] = &BTVM::vmFEof; 174 | this->functions["FileSize"] = &BTVM::vmFileSize; 175 | this->functions["FTell"] = &BTVM::vmFTell; 176 | this->functions["FSeek"] = &BTVM::vmFSeek; 177 | this->functions["ReadInt"] = &BTVM::vmReadInt; 178 | this->functions["ReadInt64"] = &BTVM::vmReadInt64; 179 | this->functions["ReadQuad"] = &BTVM::vmReadQuad; 180 | this->functions["ReadShort"] = &BTVM::vmReadShort; 181 | this->functions["ReadUInt"] = &BTVM::vmReadUInt; 182 | this->functions["ReadUInt64"] = &BTVM::vmReadUInt64; 183 | this->functions["ReadUQuad"] = &BTVM::vmReadUQuad; 184 | this->functions["ReadUShort"] = &BTVM::vmReadUShort; 185 | this->functions["ReadBytes"] = &BTVM::vmReadBytes; 186 | this->functions["ReadString"] = &BTVM::vmReadString; 187 | this->functions["ReadUShort"] = &BTVM::vmReadUShort; 188 | this->functions["LittleEndian"] = &BTVM::vmLittleEndian; 189 | this->functions["BigEndian"] = &BTVM::vmBigEndian; 190 | 191 | // String Functions: https://www.sweetscape.com/010editor/manual/FuncString.htm 192 | this->functions["Strlen"] = &BTVM::vmStrlen; 193 | 194 | // Math Functions: https://www.sweetscape.com/010editor/manual/FuncMath.htm 195 | this->functions["Ceil"] = &BTVM::vmCeil; 196 | 197 | // Tool Functions: https://www.sweetscape.com/010editor/manual/FuncTools.htm 198 | this->functions["FindAll"] = &BTVM::vmFindAll; 199 | 200 | // Non-Standard Functions 201 | this->functions["__btvm_test__"] = &BTVM::vmBtvmTest; // Non-standard BTVM function for unit testing 202 | } 203 | 204 | void BTVM::initColors() 205 | { 206 | this->_colors["cBlack"] = 0x00000000; 207 | this->_colors["cRed"] = 0x000000FF; 208 | this->_colors["cDkRed"] = 0x00000080; 209 | this->_colors["cLtRed"] = 0x008080FF; 210 | this->_colors["cGreen"] = 0x0000FF00; 211 | this->_colors["cDkGreen"] = 0x00008000; 212 | this->_colors["cLtGreen"] = 0x0080FF80; 213 | this->_colors["cBlue"] = 0x00FF0000; 214 | this->_colors["cDkBlue"] = 0x00800000; 215 | this->_colors["cLtBlue"] = 0x00FF8080; 216 | this->_colors["cPurple"] = 0x00FF00FF; 217 | this->_colors["cDkPurple"] = 0x00800080; 218 | this->_colors["cLtPurple"] = 0x00FFE0FF; 219 | this->_colors["cAqua"] = 0x00FFFF00; 220 | this->_colors["cDkAqua"] = 0x00808000; 221 | this->_colors["cLtAqua"] = 0x00FFFFE0; 222 | this->_colors["cYellow"] = 0x0000FFFF; 223 | this->_colors["cDkYellow"] = 0x00008080; 224 | this->_colors["cLtYellow"] = 0x0080FFFF; 225 | this->_colors["cDkGray"] = 0x00404040; 226 | this->_colors["cGray"] = 0x00808080; 227 | this->_colors["cSilver"] = 0x00C0C0C0; 228 | this->_colors["cLtGray"] = 0x00E0E0E0; 229 | this->_colors["cWhite"] = 0x00FFFFFF; 230 | this->_colors["cNone"] = 0xFFFFFFFF; 231 | } 232 | 233 | VMValuePtr BTVM::vmPrintf(VM *self, NCall *ncall) 234 | { 235 | VMValuePtr format = self->interpret(ncall->arguments.front()); 236 | VMFunctions::ValueList args; 237 | 238 | if(ncall->arguments.size() > 1) 239 | { 240 | for(auto it = ncall->arguments.begin() + 1; it != ncall->arguments.end(); it++) 241 | args.push_back(self->interpret(*it)); 242 | } 243 | 244 | static_cast(self)->print(VMFunctions::format_string(format, args)); 245 | return VMValuePtr(); 246 | } 247 | 248 | VMValuePtr BTVM::vmSetBackColor(VM *self, NCall *ncall) 249 | { 250 | if(ncall->arguments.size() != 1) 251 | return self->argumentError(ncall, 1); 252 | 253 | if(!node_is(ncall->arguments[0], NIdentifier)) 254 | return self->typeError(ncall->arguments[0], node_s_typename(NIdentifier)); 255 | 256 | NIdentifier* nid = static_cast(ncall->arguments[0]); 257 | static_cast(self)->_bgcolor = self->color(nid->value); 258 | return VMValuePtr(); 259 | } 260 | 261 | VMValuePtr BTVM::vmSetForeColor(VM *self, NCall *ncall) 262 | { 263 | if(ncall->arguments.size() != 1) 264 | return self->argumentError(ncall, 1); 265 | 266 | if(!node_is(ncall->arguments[0], NIdentifier)) 267 | return self->typeError(ncall->arguments[0], node_s_typename(NIdentifier)); 268 | 269 | NIdentifier* nid = static_cast(ncall->arguments.front()); 270 | static_cast(self)->_fgcolor = self->color(nid->value);; 271 | return VMValuePtr(); 272 | } 273 | 274 | VMValuePtr BTVM::vmLittleEndian(VM *self, NCall *ncall) 275 | { 276 | if(ncall->arguments.size() != 0) 277 | return self->argumentError(ncall, 0); 278 | 279 | static_cast(self)->_btvmio->setLittleEndian(); 280 | return VMValuePtr(); 281 | } 282 | 283 | VMValuePtr BTVM::vmBigEndian(VM *self, NCall *ncall) 284 | { 285 | if(ncall->arguments.size() != 0) 286 | return self->argumentError(ncall, 0); 287 | 288 | static_cast(self)->_btvmio->setBigEndian(); 289 | return VMValuePtr(); 290 | } 291 | 292 | VMValuePtr BTVM::vmFSeek(VM *self, NCall *ncall) 293 | { 294 | if(ncall->arguments.size() != 1) 295 | return self->argumentError(ncall, 1); 296 | 297 | VMValuePtr vmvalue = VMValue::copy_value(*self->interpret(ncall->arguments.front())); 298 | 299 | if(!vmvalue->is_scalar()) 300 | return self->typeError(vmvalue, "scalar"); 301 | 302 | BTVM* btvm = static_cast(self); 303 | uint64_t offset = *vmvalue->value_ref(); 304 | 305 | if(offset >= btvm->_btvmio->size()) 306 | return VMValue::allocate_literal(static_cast(-1)); 307 | 308 | btvm->_btvmio->seek(offset); 309 | return VMValue::allocate_literal(static_cast(0)); 310 | } 311 | 312 | VMValuePtr BTVM::vmStrlen(VM *self, NCall *ncall) 313 | { 314 | if(ncall->arguments.size() != 1) 315 | return self->argumentError(ncall, 1); 316 | 317 | VMValuePtr vmvalue = self->interpret(ncall->arguments.front()); 318 | 319 | if(!vmvalue->is_string()) 320 | return self->typeError(vmvalue, "string"); 321 | 322 | return VMValue::allocate_literal(static_cast(vmvalue->length())); 323 | } 324 | 325 | VMValuePtr BTVM::vmCeil(VM *self, NCall *ncall) 326 | { 327 | if(ncall->arguments.size() != 1) 328 | return self->argumentError(ncall, 1); 329 | 330 | VMValuePtr vmvalue = VMValue::copy_value(*self->interpret(ncall->arguments.front())); 331 | 332 | if(!vmvalue->is_scalar()) 333 | return self->typeError(vmvalue, "scalar"); 334 | 335 | vmvalue->d_value = std::ceil(vmvalue->d_value); 336 | return vmvalue; 337 | } 338 | 339 | VMValuePtr BTVM::vmFindAll(VM *self, NCall *ncall) 340 | { 341 | VMUnused(self); 342 | VMUnused(ncall); 343 | 344 | cout << "FindAll(): Not implemented"; 345 | return VMValuePtr(); 346 | } 347 | 348 | VMValuePtr BTVM::vmWarning(VM *self, NCall *ncall) 349 | { 350 | static_cast(self)->print("WARNING: "); 351 | return BTVM::vmPrintf(self, ncall); 352 | } 353 | 354 | VMValuePtr BTVM::vmBtvmTest(VM *self, NCall *ncall) 355 | { 356 | if(ncall->arguments.size() != 1) 357 | return self->argumentError(ncall, 1); 358 | 359 | VMValuePtr testres = self->interpret(ncall->arguments.front()); 360 | 361 | if(*testres) 362 | cout << ColorizeOk("OK") << endl; 363 | else 364 | cout << ColorizeFail("FAIL") << endl; 365 | 366 | return testres; 367 | } 368 | 369 | VMValuePtr BTVM::vmFEof(VM *self, NCall *ncall) 370 | { 371 | if(ncall->arguments.size() != 0) 372 | return self->argumentError(ncall, 0); 373 | 374 | BTVM* btvm = static_cast(self); 375 | return VMValue::allocate_literal(btvm->_btvmio->atEof()); 376 | } 377 | 378 | VMValuePtr BTVM::vmFileSize(VM *self, NCall *ncall) 379 | { 380 | if(ncall->arguments.size() != 0) 381 | return self->argumentError(ncall, 0); 382 | 383 | BTVM* btvm = static_cast(self); 384 | return VMValue::allocate_literal(btvm->_btvmio->size()); 385 | } 386 | 387 | VMValuePtr BTVM::vmFTell(VM *self, NCall *ncall) 388 | { 389 | if(ncall->arguments.size() != 0) 390 | return self->argumentError(ncall, 0); 391 | 392 | BTVM* btvm = static_cast(self); 393 | return VMValue::allocate_literal(btvm->_btvmio->offset()); 394 | } 395 | 396 | VMValuePtr BTVM::vmReadBytes(VM *self, NCall *ncall) 397 | { 398 | if(ncall->arguments.size() != 3) 399 | return self->argumentError(ncall, 3); 400 | 401 | BTVM* btvm = static_cast(self); 402 | VMValuePtr vmbuffer = self->interpret(ncall->arguments[0]); 403 | 404 | if(!vmbuffer->is_array() && !vmbuffer->is_string()) 405 | return self->typeError(vmbuffer, "array or string"); 406 | 407 | VMValuePtr vmpos = self->interpret(ncall->arguments[1]); 408 | 409 | if(!vmpos->is_scalar()) 410 | return self->typeError(vmpos, "scalar"); 411 | 412 | VMValuePtr vmn = self->interpret(ncall->arguments[2]); 413 | 414 | if(!vmn->is_scalar()) 415 | return self->typeError(vmn, "scalar"); 416 | 417 | IO_NoSeek(btvm->_btvmio); 418 | 419 | btvm->_btvmio->seek(vmpos->ui_value); 420 | btvm->_btvmio->read(vmbuffer, vmn->ui_value); 421 | return VMValuePtr(); 422 | } 423 | 424 | VMValuePtr BTVM::vmReadString(VM *self, NCall *ncall) 425 | { 426 | if((ncall->arguments.size() < 1) || (ncall->arguments.size() > 2)) 427 | return self->error("Expected 1 or 2 arguments, " + std::to_string(ncall->arguments.size()) + " given"); 428 | 429 | BTVM* btvm = static_cast(self); 430 | VMValuePtr vmpos = self->interpret(ncall->arguments[0]); 431 | 432 | if(!vmpos->is_scalar()) 433 | return self->typeError(vmpos, "scalar"); 434 | 435 | int32_t maxlen = -1; 436 | 437 | if(ncall->arguments.size() == 2) 438 | { 439 | VMValuePtr vmmaxlen = self->interpret(ncall->arguments[1]); 440 | 441 | if(vmmaxlen->is_scalar()) 442 | return self->typeError(vmmaxlen, "scalar"); 443 | 444 | maxlen = *vmmaxlen->value_ref(); 445 | } 446 | 447 | IO_NoSeek(btvm->_btvmio); 448 | 449 | VMValuePtr vmvalue = VMValue::allocate(VMValueType::String); 450 | btvm->_btvmio->seek(vmpos->ui_value); 451 | btvm->_btvmio->readString(vmvalue, maxlen); 452 | return vmvalue; 453 | } 454 | 455 | VMValuePtr BTVM::vmReadInt(VM *self, NCall *ncall) { return static_cast(self)->readScalar(ncall, 32, true); } 456 | VMValuePtr BTVM::vmReadInt64(VM *self, NCall *ncall) { return static_cast(self)->readScalar(ncall, 64, true); } 457 | VMValuePtr BTVM::vmReadQuad(VM *self, NCall *ncall) { return static_cast(self)->vmReadInt64(self, ncall); } 458 | VMValuePtr BTVM::vmReadShort(VM *self, NCall *ncall) { return static_cast(self)->readScalar(ncall, 16, true); } 459 | VMValuePtr BTVM::vmReadUInt(VM *self, NCall *ncall) { return static_cast(self)->readScalar(ncall, 32, false); } 460 | VMValuePtr BTVM::vmReadUInt64(VM *self, NCall *ncall) { return static_cast(self)->readScalar(ncall, 64, false); } 461 | VMValuePtr BTVM::vmReadUQuad(VM *self, NCall *ncall) { return static_cast(self)->vmReadUInt64(self, ncall); } 462 | VMValuePtr BTVM::vmReadUShort(VM *self, NCall *ncall) { return static_cast(self)->readScalar(ncall, 16, false); } 463 | -------------------------------------------------------------------------------- /btvm/btvm.h: -------------------------------------------------------------------------------- 1 | #ifndef BTVM_H 2 | #define BTVM_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include "vm/vm.h" 8 | #include "format/btentry.h" 9 | #include "btvmio.h" 10 | 11 | class BTVM: public VM 12 | { 13 | private: 14 | typedef std::unordered_map ColorMap; 15 | 16 | public: 17 | BTVM(BTVMIO* btvmio); 18 | ~BTVM(); 19 | virtual void parse(const std::string& code); 20 | virtual uint32_t color(const std::string& color) const; 21 | BTEntryList createTemplate(); 22 | 23 | protected: 24 | virtual void print(const std::string& s); 25 | virtual void readValue(const VMValuePtr &vmvar, uint64_t size, bool seek); 26 | virtual void entryCreated(const BTEntryPtr& btentry); 27 | virtual uint64_t currentOffset() const; 28 | virtual uint32_t currentFgColor() const; 29 | virtual uint32_t currentBgColor() const; 30 | 31 | private: 32 | BTEntryPtr createEntry(const VMValuePtr& vmvalue, const BTEntryPtr &btparent); 33 | VMValuePtr readScalar(NCall* ncall, uint64_t bits, bool issigned); 34 | void initTypes(); 35 | void initFunctions(); 36 | void initColors(); 37 | 38 | private: // Interface Functions 39 | static VMValuePtr vmPrintf(VM *self, NCall* ncall); 40 | static VMValuePtr vmSetBackColor(VM *self, NCall* ncall); 41 | static VMValuePtr vmSetForeColor(VM *self, NCall* ncall); 42 | static VMValuePtr vmWarning(VM *self, NCall* ncall); 43 | 44 | private: // I/O Functions 45 | static VMValuePtr vmFEof(VM *self, NCall* ncall); 46 | static VMValuePtr vmFileSize(VM *self, NCall* ncall); 47 | static VMValuePtr vmFTell(VM *self, NCall* ncall); 48 | static VMValuePtr vmReadBytes(VM *self, NCall* ncall); 49 | static VMValuePtr vmReadString(VM *self, NCall* ncall); 50 | static VMValuePtr vmReadInt(VM *self, NCall* ncall); 51 | static VMValuePtr vmReadInt64(VM *self, NCall* ncall); 52 | static VMValuePtr vmReadQuad(VM *self, NCall* ncall); 53 | static VMValuePtr vmReadShort(VM *self, NCall* ncall); 54 | static VMValuePtr vmReadUInt(VM *self, NCall* ncall); 55 | static VMValuePtr vmReadUInt64(VM *self, NCall* ncall); 56 | static VMValuePtr vmReadUQuad(VM *self, NCall* ncall); 57 | static VMValuePtr vmReadUShort(VM *self, NCall* ncall); 58 | static VMValuePtr vmLittleEndian(VM *self, NCall* ncall); 59 | static VMValuePtr vmBigEndian(VM *self, NCall* ncall); 60 | static VMValuePtr vmFSeek(VM *self, NCall* ncall); 61 | 62 | private: // String Functions 63 | static VMValuePtr vmStrlen(VM* self, NCall* ncall); 64 | 65 | private: // Math Functions 66 | static VMValuePtr vmCeil(VM* self, NCall* ncall); 67 | 68 | private: // Tool Functions 69 | static VMValuePtr vmFindAll(VM* self, NCall* ncall); 70 | 71 | private: // Non-Standard Functions 72 | static VMValuePtr vmBtvmTest(VM *self, NCall* ncall); 73 | 74 | private: 75 | std::unordered_map _colors; 76 | std::list _builtin; 77 | uint32_t _fgcolor; 78 | uint32_t _bgcolor; 79 | BTVMIO* _btvmio; 80 | }; 81 | 82 | #endif // BTVM_H 83 | -------------------------------------------------------------------------------- /btvm/btvm_types.cpp: -------------------------------------------------------------------------------- 1 | #include "btvm_types.h" 2 | #include 3 | 4 | /* 5 | *************** 010 Editor type definitions *************** 6 | 7 | struct TFindResults { uint64_t count; uint64_t start[]; uint64_t size[]; }; 8 | */ 9 | 10 | /* *********************************************************** */ 11 | /* ********************** Type Creation ********************** */ 12 | /* *********************************************************** */ 13 | 14 | #define identifier(id) (new NIdentifier(id)) 15 | #define empty_block() (new NBlock()) 16 | 17 | static NScalarType* buildScalar(const std::string& name, uint64_t bits, bool issigned) 18 | { 19 | NScalarType* nscalar = new NScalarType(name, bits); 20 | nscalar->is_signed = issigned; 21 | return nscalar; 22 | } 23 | 24 | static NVariable* buildVariable(const std::string& name, Node* ntype, Node* nsize = NULL) 25 | { 26 | NVariable* nvar = new NVariable(identifier(name)); 27 | nvar->type = ntype; 28 | nvar->size = nsize; 29 | return nvar; 30 | } 31 | 32 | static NStruct* buildStruct(const std::string& name, const NodeList& members) { return new NStruct(identifier(name), NodeList(), members); } 33 | 34 | /* ******************************************************* */ 35 | /* ********************** Built-ins ********************** */ 36 | /* ******************************************************* */ 37 | 38 | Node *BTVMTypes::buildTFindResults() 39 | { 40 | NodeList members; 41 | members.push_back(buildVariable("count", buildScalar("uint64", 32, false))); 42 | members.push_back(buildVariable("start", buildScalar("uint64", 32, false), empty_block())); 43 | members.push_back(buildVariable("size", buildScalar("uint64", 32, false), empty_block())); 44 | 45 | return buildStruct("TFindResults", members); 46 | } 47 | -------------------------------------------------------------------------------- /btvm/btvm_types.h: -------------------------------------------------------------------------------- 1 | #ifndef BTVM_TYPES_H 2 | #define BTVM_TYPES_H 3 | 4 | #include "vm/ast.h" 5 | 6 | namespace BTVMTypes 7 | { 8 | Node* buildTFindResults(); 9 | } 10 | 11 | #endif // BTVM_TYPES_H 12 | -------------------------------------------------------------------------------- /btvm/btvmio.cpp: -------------------------------------------------------------------------------- 1 | #include "btvmio.h" 2 | #include "vm/ast.h" 3 | #include 4 | 5 | #define BUFFER_SIZE 4096 6 | #define align_to(x, a) (x + (a - (x % a))) 7 | #define is_bigendian() (*reinterpret_cast(&BTVMIO::PLATFORM_ENDIANNESS) == 0) 8 | 9 | const int BTVMIO::PLATFORM_ENDIANNESS = 1; 10 | 11 | BTVMIO::BTVMIO(): _buffersize(0) 12 | { 13 | this->_platformendianness = this->_endianness = is_bigendian() ? BTEndianness::BigEndian : BTEndianness::LittleEndian; 14 | this->_buffer = static_cast(malloc(BUFFER_SIZE)); 15 | } 16 | 17 | BTVMIO::~BTVMIO() 18 | { 19 | free(this->_buffer); 20 | this->_buffer = NULL; 21 | } 22 | 23 | void BTVMIO::read(const VMValuePtr &vmvalue, uint64_t bytes) 24 | { 25 | if(!vmvalue) 26 | { 27 | this->walk(bytes); 28 | return; 29 | } 30 | 31 | if(vmvalue->value_bits != -1) 32 | { 33 | uint64_t bits = vmvalue->value_bits == -1 ? (bytes * PLATFORM_BITS) : static_cast(vmvalue->value_bits); 34 | this->_cursor.size = bytes; 35 | this->readBits(vmvalue->value_ref(), bits); 36 | } 37 | else 38 | { 39 | this->alignCursor(); 40 | this->readBytes(vmvalue->value_ref(), bytes); 41 | this->elaborateEndianness(vmvalue); 42 | } 43 | } 44 | 45 | void BTVMIO::readString(const VMValuePtr &vmvalue, int64_t maxlen) 46 | { 47 | uint8_t* sbuffer = this->_buffer + this->_cursor.rel_position; 48 | this->alignCursor(); 49 | 50 | while(!this->atEof() && maxlen) 51 | { 52 | if(this->atBufferEnd()) 53 | sbuffer = this->updateBuffer(); 54 | 55 | vmvalue->s_value.push_back(*sbuffer); 56 | 57 | if((maxlen == -1) && (*sbuffer == '\0')) 58 | break; 59 | else if(maxlen > 0) 60 | maxlen--; 61 | 62 | sbuffer++; this->_cursor++; 63 | } 64 | } 65 | 66 | void BTVMIO::walk(uint64_t steps) 67 | { 68 | if(!steps) 69 | return; 70 | 71 | this->alignCursor(); 72 | this->seek(this->_cursor.position + steps); 73 | } 74 | 75 | uint64_t BTVMIO::offset() const 76 | { 77 | return this->_cursor.position; 78 | } 79 | 80 | bool BTVMIO::atEof() const 81 | { 82 | if(!this->_buffer || this->_cursor.hasBits() || !this->_cursor.moved) 83 | return false; 84 | 85 | return (this->_buffersize < BUFFER_SIZE) && (this->_cursor.rel_position >= this->_buffersize); 86 | } 87 | 88 | void BTVMIO::seek(uint64_t offset) 89 | { 90 | this->_cursor.position = offset; 91 | this->updateBuffer(); 92 | } 93 | 94 | int BTVMIO::endianness() const 95 | { 96 | return this->_endianness; 97 | } 98 | 99 | void BTVMIO::setLittleEndian() 100 | { 101 | this->_endianness = BTEndianness::LittleEndian; 102 | } 103 | 104 | void BTVMIO::setBigEndian() 105 | { 106 | this->_endianness = BTEndianness::BigEndian; 107 | } 108 | 109 | uint8_t BTVMIO::readBit() 110 | { 111 | uint8_t* sbuffer = this->_buffer + this->_cursor.rel_position; 112 | uint8_t val = (*sbuffer & (1u << this->_cursor.bit)) >> this->_cursor.bit; 113 | 114 | this->_cursor.bit++; 115 | 116 | if(this->_cursor.bit == PLATFORM_BITS) 117 | { 118 | this->_cursor++; 119 | this->_cursor.bit = 0; 120 | } 121 | 122 | return val; 123 | } 124 | 125 | uint8_t* BTVMIO::updateBuffer() 126 | { 127 | this->_buffersize = this->readData(this->_buffer, BUFFER_SIZE); 128 | this->_cursor.rewind(); 129 | return this->_buffer; 130 | } 131 | 132 | bool BTVMIO::atBufferEnd() const 133 | { 134 | if(this->_cursor.hasBits()) 135 | return false; 136 | 137 | return this->_cursor.rel_position >= this->_buffersize; 138 | } 139 | 140 | void BTVMIO::alignCursor() 141 | { 142 | if(!this->_cursor.hasBits() || !this->_cursor.size) 143 | return; 144 | 145 | this->_cursor.position = align_to(this->_cursor.position, this->_cursor.size); 146 | this->_cursor.rel_position = align_to(this->_cursor.rel_position, this->_cursor.size); 147 | this->_cursor.size = this->_cursor.bit = 0; 148 | } 149 | 150 | void BTVMIO::readBytes(uint8_t *buffer, uint64_t bytescount) 151 | { 152 | uint8_t* sbuffer = this->_buffer + this->_cursor.rel_position; 153 | uint8_t* dbuffer = buffer; 154 | 155 | for(uint64_t i = 0; i < bytescount && !this->atEof(); i++) 156 | { 157 | if(this->atBufferEnd()) 158 | sbuffer = this->updateBuffer(); 159 | 160 | *dbuffer = *sbuffer; 161 | sbuffer++; dbuffer++; 162 | 163 | this->_cursor++; 164 | } 165 | } 166 | 167 | void BTVMIO::readBits(uint8_t *buffer, uint64_t bitscount) 168 | { 169 | uint8_t* dbuffer = buffer; 170 | 171 | for(uint64_t i = 0; i < bitscount && !this->atEof(); i++) 172 | { 173 | if(this->atBufferEnd()) 174 | this->updateBuffer(); 175 | 176 | *dbuffer |= this->readBit(); 177 | 178 | if(!this->_cursor.bit) 179 | { 180 | dbuffer++; 181 | *dbuffer = 0; 182 | } 183 | } 184 | } 185 | 186 | void BTVMIO::elaborateEndianness(const VMValuePtr &vmvalue) const 187 | { 188 | if(vmvalue->value_type == VMValueType::s16) 189 | *vmvalue->value_ref() = this->elaborateEndianness(*vmvalue->value_ref()); 190 | else if((vmvalue->value_type == VMValueType::s32) || (vmvalue->value_type == VMValueType::Float)) 191 | *vmvalue->value_ref() = this->elaborateEndianness(*vmvalue->value_ref()); 192 | else if((vmvalue->value_type == VMValueType::s64) || (vmvalue->value_type == VMValueType::Double)) 193 | *vmvalue->value_ref() = this->elaborateEndianness(*vmvalue->value_ref()); 194 | else if(vmvalue->value_type == VMValueType::u16) 195 | *vmvalue->value_ref() = this->elaborateEndianness(*vmvalue->value_ref()); 196 | else if(vmvalue->value_type == VMValueType::u32) 197 | *vmvalue->value_ref() = this->elaborateEndianness(*vmvalue->value_ref()); 198 | else if(vmvalue->value_type == VMValueType::u64) 199 | *vmvalue->value_ref() = this->elaborateEndianness(*vmvalue->value_ref()); 200 | } 201 | -------------------------------------------------------------------------------- /btvm/btvmio.h: -------------------------------------------------------------------------------- 1 | #ifndef BTVMIO_H 2 | #define BTVMIO_H 3 | 4 | #include 5 | #include "vm/vmvalue.h" 6 | #include "vm/vm_functions.h" 7 | #include "format/btentry.h" 8 | 9 | #define IO_NoSeek(btvmio) BTVMIO::NoSeek __noseek__(btvmio) 10 | 11 | class BTVMIO 12 | { 13 | private: 14 | struct BitCursor { 15 | BitCursor(): position(0), rel_position(0), bit(0), size(0), moved(false) { } 16 | void rewind() { rel_position = bit = size = 0; moved = true; } 17 | bool hasBits() const { return bit > 0; } 18 | BitCursor& operator++(int) { position++; rel_position++; moved = true; return *this; } 19 | uint64_t position, rel_position, bit, size; 20 | bool moved; 21 | }; 22 | 23 | public: 24 | struct NoSeek { 25 | NoSeek(BTVMIO* btvmio): _btvmio(btvmio), _oldcursor(_btvmio->_cursor) { } 26 | ~NoSeek() { _btvmio->seek(_oldcursor.position); } 27 | 28 | private: 29 | BTVMIO* _btvmio; 30 | BitCursor _oldcursor; 31 | }; 32 | 33 | public: 34 | BTVMIO(); 35 | virtual ~BTVMIO(); 36 | void read(const VMValuePtr &vmvalue, uint64_t bytes); 37 | void readString(const VMValuePtr &vmvalue, int64_t maxlen); 38 | void walk(uint64_t steps); 39 | uint64_t offset() const; 40 | bool atEof() const; 41 | 42 | public: 43 | virtual void seek(uint64_t offset); 44 | virtual uint64_t size() const = 0; 45 | 46 | public: 47 | int endianness() const; 48 | void setLittleEndian(); 49 | void setBigEndian(); 50 | 51 | private: 52 | uint8_t readBit(); 53 | uint8_t *updateBuffer(); 54 | bool atBufferEnd() const; 55 | void alignCursor(); 56 | void readBytes(uint8_t* buffer, uint64_t bytescount); 57 | void readBits(uint8_t* buffer, uint64_t bitscount); 58 | 59 | protected: 60 | virtual uint64_t readData(uint8_t* buffer, uint64_t size) = 0; 61 | 62 | private: 63 | template T elaborateEndianness(T valueref) const; 64 | void elaborateEndianness(const VMValuePtr &vmvalue) const; 65 | 66 | private: 67 | static const int PLATFORM_ENDIANNESS; 68 | int _platformendianness; 69 | int _endianness; 70 | BitCursor _cursor; 71 | uint64_t _buffersize; 72 | uint8_t* _buffer; 73 | }; 74 | 75 | template T BTVMIO::elaborateEndianness(T value) const 76 | { 77 | if(this->_platformendianness == this->_endianness) 78 | return value; 79 | 80 | uint8_t *start, *end; 81 | 82 | for(start = reinterpret_cast(&value), end = start + sizeof(T) - 1; start < end; ++start, --end) 83 | { 84 | uint8_t swap = *start; 85 | *start = *end; 86 | *end = swap; 87 | } 88 | 89 | return value; 90 | } 91 | #endif // BTVMIO_H 92 | -------------------------------------------------------------------------------- /btvm/format/btentry.h: -------------------------------------------------------------------------------- 1 | #ifndef BTENTRY_H 2 | #define BTENTRY_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include "../vm/vmvalue.h" 8 | 9 | enum BTEndianness 10 | { 11 | LittleEndian, 12 | BigEndian, 13 | }; 14 | 15 | struct BTLocation 16 | { 17 | BTLocation(): offset(0), size(0) { } 18 | BTLocation(uint64_t offset, uint64_t size): offset(offset), size(size) { } 19 | uint64_t end() const { return (offset + size) - 1; } 20 | 21 | uint64_t offset; 22 | uint64_t size; 23 | }; 24 | 25 | class BTEntry; 26 | 27 | typedef std::shared_ptr BTEntryPtr; 28 | typedef std::vector BTEntryList; 29 | 30 | struct BTEntry 31 | { 32 | BTEntry() { } 33 | BTEntry(const VMValuePtr& value, size_t endianness): name(value->value_id), value(value), endianness(endianness) { } 34 | 35 | std::string name; 36 | VMValuePtr value; 37 | BTLocation location; 38 | size_t endianness; 39 | BTEntryPtr parent; 40 | BTEntryList children; 41 | }; 42 | 43 | 44 | #endif // BTENTRY_H 45 | -------------------------------------------------------------------------------- /btvm/vm/ast.cpp: -------------------------------------------------------------------------------- 1 | #include "ast.h" 2 | #include "vm_functions.h" 3 | 4 | using namespace std; 5 | 6 | unsigned long long Node::global_id = 0; 7 | 8 | #define dump_object_name __xml_dump__ 9 | #define create_dump_object(n) XMLNode dump_object_name(node_typename(n)); 10 | #define return_dump_object return dump_object_name 11 | 12 | #define get_attribute(n, t, a) (static_cast(n)->a) 13 | #define is_attribute_valid get_attribute 14 | 15 | #define set_simple_attribute(a) dump_object_name.attribute = a 16 | #define set_main_attribute(n, t, a) dump_object_name.attribute = get_attribute(n, t, a) 17 | #define dump_main_attribute(n, t, a) dump_object_name.attribute = dump_ast(get_attribute(n, t, a)) 18 | #define dump_node_attribute(n, t, a) dump_object_name.put(get_attribute(n, t, a), #a) 19 | 20 | #define dump_attributes(n, t, a) std::for_each(get_attribute(n, t, a).begin(), \ 21 | get_attribute(n, t, a).end(), \ 22 | [&dump_object_name](Node* __n__) { dump_ast(__n__); }) 23 | 24 | #define xml_open_tag(x) ("<" + x + ">\n") 25 | #define xml_open_tag_attr(x, a) ("<" + x + " id=\"" + a + "\">\n") 26 | #define xml_close_tag(x) ("\n") 27 | 28 | struct XMLNode 29 | { 30 | XMLNode(const string& name, const string& attribute = string()): name(name), attribute(attribute) { } 31 | void put(const string& s) { content += s; } 32 | 33 | void put(Node* node, const string& attribute = string()) 34 | { 35 | XMLNode n(node->__type__(), attribute); 36 | n.put(dump_ast(node)); 37 | 38 | this->put(n); 39 | } 40 | 41 | void put(const NodeList& nodes, const string& attribute = string()) 42 | { 43 | XMLNode n("NodeList", attribute); 44 | 45 | for(auto it = nodes.begin(); it != nodes.end(); it++) 46 | n.put(dump_ast(*it)); 47 | 48 | this->put(n); 49 | } 50 | 51 | operator string() const { return (attribute.empty() ? xml_open_tag(name) : xml_open_tag_attr(name, attribute)) + content + xml_close_tag(name); } 52 | 53 | string name; 54 | string attribute; 55 | string content; 56 | }; 57 | 58 | string dump_ast(Node *n) 59 | { 60 | create_dump_object(n); 61 | 62 | if(node_is(n, NVMState)) 63 | { 64 | if(get_attribute(n, NVMState, state) == VMState::Continue) 65 | set_simple_attribute("continue"); 66 | else if(get_attribute(n, NVMState, state) == VMState::Break) 67 | set_simple_attribute("break"); 68 | else if(get_attribute(n, NVMState, state) == VMState::Return) 69 | set_simple_attribute("return"); 70 | else 71 | set_simple_attribute(std::to_string(get_attribute(n, NVMState, state))); 72 | } 73 | else if(node_is(n, NCustomVariable)) 74 | { 75 | set_main_attribute(n, NCustomVariable, action); 76 | dump_node_attribute(n, NCustomVariable, value); 77 | } 78 | else if(node_inherits(n, NVariable)) 79 | { 80 | dump_main_attribute(n, NVariable, type); 81 | dump_node_attribute(n, NVariable, name); 82 | 83 | if(is_attribute_valid(n, NVariable, value)) 84 | dump_node_attribute(n, NVariable, value); 85 | 86 | if(is_attribute_valid(n, NVariable, bits)) 87 | dump_node_attribute(n, NVariable, bits); 88 | } 89 | else if(node_is(n, NFunction)) 90 | { 91 | dump_main_attribute(n, NFunction, name); 92 | dump_node_attribute(n, NFunction, arguments); 93 | dump_node_attribute(n, NFunction, body); 94 | } 95 | else if(node_is(n, NEnumValue)) 96 | { 97 | dump_main_attribute(n, NEnumValue, name); 98 | 99 | if(is_attribute_valid(n, NEnumValue, value)) 100 | dump_node_attribute(n, NEnumValue, value); 101 | } 102 | else if(node_is(n, NEnum)) 103 | { 104 | dump_main_attribute(n, NEnum, name); 105 | dump_node_attribute(n, NEnum, members); 106 | } 107 | else if(node_is(n, NCall)) 108 | { 109 | dump_main_attribute(n, NCall, name); 110 | dump_node_attribute(n, NCall, arguments); 111 | } 112 | else if(node_is(n, NCast)) 113 | { 114 | dump_main_attribute(n, NCast, cast); 115 | dump_node_attribute(n, NCast, expression); 116 | } 117 | else if(node_is(n, NConditional)) 118 | { 119 | dump_node_attribute(n, NConditional, condition); 120 | dump_node_attribute(n, NConditional, true_block); 121 | } 122 | else if(node_is(n, NCompareOperator)) 123 | { 124 | set_main_attribute(n, NCompareOperator, cmp); 125 | dump_node_attribute(n, NCompareOperator, left); 126 | dump_node_attribute(n, NCompareOperator, right); 127 | } 128 | else if(node_is(n, NCase)) 129 | { 130 | if(is_attribute_valid(n, NCase, value)) 131 | dump_main_attribute(n, NCase, value); 132 | else 133 | set_simple_attribute("default"); 134 | 135 | dump_node_attribute(n, NCase, body); 136 | } 137 | else if(node_is(n, NFor)) 138 | { 139 | dump_node_attribute(n, NFor, counter); 140 | dump_node_attribute(n, NFor, condition); 141 | dump_node_attribute(n, NFor, update); 142 | } 143 | else if(node_is(n, NTypedef)) 144 | { 145 | dump_main_attribute(n, NTypedef, name); 146 | dump_node_attribute(n, NTypedef, type); 147 | dump_node_attribute(n, NTypedef, custom_vars); 148 | } 149 | else if(node_is(n, NIndexOperator)) 150 | { 151 | dump_node_attribute(n, NIndexOperator, index); 152 | dump_node_attribute(n, NIndexOperator, expression); 153 | } 154 | else if(node_is(n, NUnaryOperator)) 155 | { 156 | set_main_attribute(n, NUnaryOperator, op); 157 | dump_node_attribute(n, NUnaryOperator, expression); 158 | } 159 | else if(node_inherits(n, NBinaryOperator)) 160 | { 161 | set_main_attribute(n, NBinaryOperator, op); 162 | dump_node_attribute(n, NBinaryOperator, left); 163 | dump_node_attribute(n, NBinaryOperator, right); 164 | } 165 | else if(node_inherits(n, NWhile)) 166 | { 167 | dump_node_attribute(n, NWhile, condition); 168 | dump_node_attribute(n, NWhile, true_block); 169 | } 170 | else if(node_inherits(n, NCompoundType)) 171 | { 172 | dump_main_attribute(n, NCompoundType, name); 173 | dump_node_attribute(n, NCompoundType, members); 174 | } 175 | else if(node_is(n, NSizeOf)) 176 | dump_node_attribute(n, NSizeOf, expression); 177 | else if(node_is(n, NReturn)) 178 | dump_node_attribute(n, NReturn, block); 179 | else if(node_is(n, NBlock)) 180 | dump_node_attribute(n, NBlock, statements); 181 | else if(node_is(n, NSwitch)) 182 | dump_attributes(n, NSwitch, cases); 183 | else if(node_is(n, NIdentifier)) 184 | return get_attribute(n, NIdentifier, value); 185 | else if(node_is(n, NString)) 186 | return get_attribute(n, NString, value); 187 | else if(node_is(n, NBoolean)) 188 | return get_attribute(n, NBoolean, value) ? "true" : "false"; 189 | else if(node_is(n, NInteger)) 190 | return std::to_string(get_attribute(n, NInteger, value)); 191 | else if(node_is(n, NReal)) 192 | return std::to_string(get_attribute(n, NReal, value)); 193 | else if(node_inherits(n, NType)) 194 | return dump_ast(static_cast(n)->name); 195 | else 196 | throw std::runtime_error("Cannot dump '" + node_typename(n) + "'"); 197 | 198 | return_dump_object; 199 | } 200 | -------------------------------------------------------------------------------- /btvm/vm/ast.h: -------------------------------------------------------------------------------- 1 | #ifndef AST_H 2 | #define AST_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include "vmvalue.h" 10 | 11 | class VM; 12 | struct Node; 13 | 14 | typedef std::vector NodeList; 15 | struct delete_node { template void operator()(T t) { delete t; } }; 16 | 17 | #define AST_NODE(x) virtual std::string __type__() const { return #x; } 18 | #define delete_nodelist(n) std::for_each(n.begin(), n.end(), delete_node()) 19 | #define delete_if(n) if(n) delete n 20 | 21 | #define anonymous_type_prefix "__anonymous_decl__" 22 | #define anonymous_identifier (new NIdentifier(anonymous_type_prefix + std::to_string(global_id++) + "__")) 23 | #define is_anonymous_identifier(nid) (nid->value.find(anonymous_type_prefix) == 0) 24 | 25 | #define node_s_typename(n) #n 26 | #define node_typename(n) ((n)->__type__()) 27 | #define node_is(n, t) (n && ((n)->__type__() == #t)) 28 | #define node_inherits(n, t) (n && dynamic_cast(n)) 29 | #define node_is_compound(n) node_inherits(n, NCompoundType) 30 | 31 | struct Node 32 | { 33 | Node() { } 34 | virtual ~Node() { } 35 | virtual std::string __type__() const = 0; 36 | 37 | protected: 38 | static unsigned long long global_id; 39 | }; 40 | 41 | // --------------------------------------------------------- 42 | // Basic Nodes 43 | // --------------------------------------------------------- 44 | 45 | struct NLiteral: public Node 46 | { 47 | AST_NODE(NLiteral) 48 | 49 | NLiteral(): Node() { } 50 | }; 51 | 52 | struct NBoolean: public NLiteral 53 | { 54 | AST_NODE(NBoolean) 55 | 56 | NBoolean(bool value): NLiteral(), value(value) { } 57 | 58 | bool value; 59 | }; 60 | 61 | struct NInteger: public NLiteral 62 | { 63 | AST_NODE(NInteger) 64 | 65 | NInteger(int64_t value): NLiteral(), value(value) { } 66 | 67 | int64_t value; 68 | }; 69 | 70 | struct NReal: public NLiteral 71 | { 72 | AST_NODE(NReal) 73 | 74 | NReal(double value): NLiteral(), value(value) { } 75 | 76 | double value; 77 | }; 78 | 79 | struct NString: public NLiteral 80 | { 81 | AST_NODE(NString) 82 | 83 | NString(const std::string& value): NLiteral(), value(value) { } 84 | 85 | std::string value; 86 | }; 87 | 88 | struct NIdentifier: public Node 89 | { 90 | AST_NODE(NIdentifier) 91 | 92 | NIdentifier(const std::string& value): Node(), value(value) { } 93 | 94 | std::string value; 95 | }; 96 | 97 | struct NEnumValue: public Node 98 | { 99 | AST_NODE(NEnumValue) 100 | 101 | NEnumValue(NIdentifier* id): Node(), name(id), value(NULL) { } 102 | NEnumValue(NIdentifier* id, Node* value): Node(), name(id), value(value) { } 103 | ~NEnumValue() { delete name; delete_if(value); } 104 | 105 | NIdentifier* name; 106 | Node* value; 107 | }; 108 | 109 | struct NCustomVariable: public Node 110 | { 111 | AST_NODE(NCustomVariable) 112 | 113 | NCustomVariable(const std::string& action, Node* value): Node(), action(action), value(value) { } 114 | 115 | std::string action; 116 | Node* value; 117 | }; 118 | 119 | struct NType: public Node 120 | { 121 | AST_NODE(NType) 122 | 123 | NType(const std::string& name): Node(), name(new NIdentifier(name)), size(NULL), is_basic(false), is_compound(false) { } 124 | NType(NIdentifier* name, const NodeList& customvars): Node(), name(name), size(NULL), custom_vars(customvars), is_basic(false), is_compound(false) { } 125 | NType(NIdentifier* name): Node(), name(name), size(NULL), is_basic(false), is_compound(false) { } 126 | ~NType() { delete name; delete_if(size); delete_nodelist(custom_vars); } 127 | 128 | NIdentifier* name; 129 | Node* size; 130 | NodeList custom_vars; 131 | bool is_basic; 132 | bool is_compound; 133 | }; 134 | 135 | struct NBasicType: public NType 136 | { 137 | AST_NODE(NBasicType) 138 | 139 | NBasicType(const std::string& name, uint64_t bits): NType(name), bits(bits), is_signed(true) { is_basic = true; } 140 | 141 | uint64_t bits; 142 | bool is_signed; 143 | }; 144 | 145 | struct NCompoundType: public NType 146 | { 147 | AST_NODE(NCompoundType) 148 | 149 | NCompoundType(const NodeList& arguments, const NodeList& members): NType(anonymous_identifier), arguments(arguments), members(members) { is_basic = false; is_compound = true; } 150 | NCompoundType(NIdentifier* id, const NodeList& arguments, const NodeList& members): NType(id), arguments(arguments), members(members) { is_basic = false; is_compound = true; } 151 | NCompoundType(const NodeList& arguments, const NodeList& members, const NodeList& customvars): NType(anonymous_identifier, customvars), arguments(arguments), members(members) { is_basic = false; is_compound = true; } 152 | NCompoundType(NIdentifier* id, const NodeList& arguments, const NodeList& members, const NodeList& customvars): NType(id, customvars), arguments(arguments), members(members) { is_basic = false; is_compound = true; } 153 | 154 | NodeList arguments; 155 | NodeList members; 156 | }; 157 | 158 | struct NBooleanType: public NBasicType 159 | { 160 | AST_NODE(NBooleanType) 161 | 162 | NBooleanType(const std::string& name): NBasicType(name, 8) { } 163 | }; 164 | 165 | struct NScalarType: public NBasicType 166 | { 167 | AST_NODE(NScalarType) 168 | 169 | NScalarType(const std::string& name, uint64_t bits): NBasicType(name, bits), is_fp(false) { } 170 | 171 | bool is_fp; 172 | }; 173 | 174 | struct NCharType: public NScalarType 175 | { 176 | AST_NODE(NCharType) 177 | 178 | NCharType(const std::string& name): NScalarType(name, 8) { } 179 | }; 180 | 181 | struct NStringType: public NBasicType 182 | { 183 | AST_NODE(NStringType) 184 | 185 | NStringType(const std::string& name): NBasicType(name, 8) { is_signed = true; } 186 | }; 187 | 188 | struct NDosDate: public NScalarType 189 | { 190 | AST_NODE(NDosDate) 191 | 192 | NDosDate(const std::string& name): NScalarType(name, 16) { is_signed = false; } 193 | }; 194 | 195 | struct NDosTime: public NScalarType 196 | { 197 | AST_NODE(NDosTime) 198 | 199 | NDosTime(const std::string& name): NScalarType(name, 16) { is_signed = false; } 200 | }; 201 | 202 | struct NTime: public NScalarType 203 | { 204 | AST_NODE(NTime) 205 | 206 | NTime(const std::string& name): NScalarType(name, 32) { is_signed = false; } 207 | }; 208 | 209 | struct NFileTime: public NScalarType 210 | { 211 | AST_NODE(NFileTime) 212 | 213 | NFileTime(const std::string& name): NScalarType(name, 64) { is_signed = false; } 214 | }; 215 | 216 | struct NOleTime: public NScalarType 217 | { 218 | AST_NODE(NOleTime) 219 | 220 | NOleTime(const std::string& name): NScalarType(name, 64) { is_signed = false; } 221 | }; 222 | 223 | struct NEnum: public NCompoundType 224 | { 225 | AST_NODE(NEnum) 226 | 227 | NEnum(const NodeList& members, NType* type): NCompoundType(NodeList(), members), type(type) { this->type = (type ? type : new NScalarType("int", 32)); } 228 | NEnum(NIdentifier* id, const NodeList& members, NType* type): NCompoundType(id, NodeList(), members), type(type) { this->type = (type ? type : new NScalarType("int", 32)); } 229 | NEnum(const NodeList& members, const NodeList& customvars, NType* type): NCompoundType(NodeList(), members, customvars), type(type) { this->type = (type ? type : new NScalarType("int", 32)); } 230 | NEnum(NIdentifier* id, const NodeList& members, const NodeList& customvars, NType* type): NCompoundType(id, NodeList(), members, customvars), type(type) { this->type = (type ? type : new NScalarType("int", 32)); } 231 | ~NEnum() { delete_if(type); } 232 | 233 | NType* type; 234 | }; 235 | 236 | struct NBlock: public Node 237 | { 238 | AST_NODE(NBlock) 239 | 240 | NBlock(): Node() { } 241 | NBlock(const NodeList& statements): Node(), statements(statements) { } 242 | ~NBlock() { delete_nodelist(statements); } 243 | 244 | NodeList statements; 245 | }; 246 | 247 | struct NVariable: public Node 248 | { 249 | AST_NODE(NVariable) 250 | 251 | NVariable(Node* bits): Node(), type(NULL), name(anonymous_identifier), value(NULL), size(NULL), bits(bits), is_const(false), is_local(false) { } 252 | NVariable(NIdentifier* name, Node* size): Node(), type(NULL), name(name), value(NULL), size(size), bits(NULL), is_const(false), is_local(false) { } 253 | NVariable(NIdentifier* name, Node* size, Node* bits): Node(), type(NULL), name(name), value(NULL), size(size), bits(bits), is_const(false), is_local(false) { } 254 | virtual ~NVariable() { delete type; delete name; delete_if(value); delete size; } 255 | 256 | Node* type; 257 | NIdentifier* name; 258 | NodeList names; 259 | NodeList custom_vars; 260 | NodeList constructor; // For Struct and Unions 261 | Node* value; 262 | Node* size; 263 | Node* bits; 264 | bool is_const; 265 | bool is_local; 266 | }; 267 | 268 | struct NArgument: public NVariable 269 | { 270 | AST_NODE(NArgument) 271 | 272 | NArgument(Node* type, NIdentifier* name, Node* size): NVariable(name, size), by_reference(false) { this->type = type; this->is_local = true; } 273 | 274 | bool by_reference; 275 | }; 276 | 277 | // --------------------------------------------------------- 278 | // Statement Nodes 279 | // --------------------------------------------------------- 280 | 281 | struct NReturn: public Node 282 | { 283 | AST_NODE(NReturn) 284 | 285 | NReturn(NBlock* block): Node(), block(block) { } 286 | ~NReturn() { delete block; } 287 | 288 | NBlock* block; 289 | }; 290 | 291 | struct NBinaryOperator: public Node 292 | { 293 | AST_NODE(NBinaryOperator) 294 | 295 | NBinaryOperator(Node* left, const std::string& op, Node* right): Node(), left(left), op(op), right(right) { } 296 | ~NBinaryOperator() { delete left; delete right; } 297 | 298 | Node* left; 299 | std::string op; 300 | Node* right; 301 | }; 302 | 303 | struct NUnaryOperator: public Node 304 | { 305 | AST_NODE(NUnaryOperator) 306 | 307 | NUnaryOperator(const std::string& op, Node* expression, bool prefix): Node(), op(op), expression(expression), is_prefix(prefix) { } 308 | ~NUnaryOperator() { delete expression; } 309 | 310 | std::string op; 311 | Node* expression; 312 | bool is_prefix; 313 | }; 314 | 315 | struct NDotOperator: public NBinaryOperator 316 | { 317 | AST_NODE(NDotOperator) 318 | 319 | NDotOperator(Node* left, NIdentifier* right): NBinaryOperator(left, ".", right) { } 320 | }; 321 | 322 | struct NIndexOperator: public Node 323 | { 324 | AST_NODE(NIndexOperator) 325 | 326 | NIndexOperator(Node* expression, Node* index): Node(), expression(expression), index(index) { } 327 | ~NIndexOperator() { delete index; } 328 | 329 | Node* expression; 330 | Node* index; 331 | }; 332 | 333 | struct NCompareOperator: public Node 334 | { 335 | AST_NODE(NCompareOperator) 336 | 337 | NCompareOperator(Node* lhs, Node* rhs, const std::string& cmp): Node(), left(lhs), right(rhs), cmp(cmp) { } 338 | ~NCompareOperator() { delete left; delete right; } 339 | 340 | Node* left; 341 | Node* right; 342 | std::string cmp; 343 | }; 344 | 345 | struct NConditional: public Node 346 | { 347 | AST_NODE(NConditional) 348 | 349 | NConditional(Node* condition, Node* trueblock): Node(), condition(condition), true_block(trueblock), false_block(NULL) { } 350 | NConditional(Node* condition, Node* trueblock, Node* falseblock): Node(), condition(condition), true_block(trueblock), false_block(falseblock) { } 351 | ~NConditional() { delete condition; delete true_block; delete_if(false_block); } 352 | 353 | Node* condition; 354 | Node* true_block; 355 | Node* false_block; 356 | }; 357 | 358 | struct NWhile: public NConditional 359 | { 360 | AST_NODE(NWhile) 361 | 362 | NWhile(Node* condition, Node* trueblock): NConditional(condition, trueblock) { } 363 | }; 364 | 365 | struct NDoWhile: public NWhile 366 | { 367 | AST_NODE(NDoWhile) 368 | 369 | NDoWhile(Node* body, Node* condition): NWhile(condition, body) { } 370 | }; 371 | 372 | struct NFor: public NConditional 373 | { 374 | AST_NODE(NFor) 375 | 376 | NFor(Node* counter, Node* condition, Node* update, Node* trueblock): NConditional(condition, trueblock), counter(counter), update(update) { } 377 | ~NFor() { delete counter; delete update; } 378 | 379 | Node* counter; 380 | Node* update; 381 | }; 382 | 383 | struct NSizeOf: public Node 384 | { 385 | AST_NODE(NSizeOf) 386 | 387 | NSizeOf(Node* expression): Node(), expression(expression) { } 388 | ~NSizeOf() { delete expression; } 389 | 390 | Node* expression; 391 | }; 392 | 393 | struct NVMState: public Node 394 | { 395 | AST_NODE(NVMState) 396 | 397 | NVMState(int state): Node(), state(state) { } 398 | 399 | int state; 400 | }; 401 | 402 | struct NCase: public Node 403 | { 404 | AST_NODE(NCase) 405 | 406 | NCase(Node* body): Node(), value(NULL), body(body) { } 407 | NCase(Node* value, Node* body): Node(), value(value), body(body) { } 408 | ~NCase() { delete_if(value); delete body; } 409 | 410 | Node* value; 411 | Node* body; 412 | }; 413 | 414 | struct NSwitch: public Node 415 | { 416 | AST_NODE(NSwitch) 417 | 418 | NSwitch(Node* expression, const NodeList& cases): Node(), cases(cases), expression(expression), defaultcase(NULL) { } 419 | ~NSwitch() { delete expression; delete_if(defaultcase); /* delete_nodelist(cases); */ } 420 | 421 | NodeList cases; 422 | Node* expression; 423 | Node* defaultcase; 424 | }; 425 | 426 | struct NStruct: public NCompoundType 427 | { 428 | AST_NODE(NStruct) 429 | 430 | NStruct(const NodeList& arguments, const NodeList& members): NCompoundType(arguments, members) { } 431 | NStruct(NIdentifier* id, const NodeList& arguments, const NodeList& members): NCompoundType(id, arguments, members) { } 432 | NStruct(const NodeList& arguments, const NodeList& members, const NodeList& customvars): NCompoundType(arguments, members, customvars) { } 433 | NStruct(NIdentifier* id, const NodeList& arguments, const NodeList& members, const NodeList& customvars): NCompoundType(id, arguments, members, customvars) { } 434 | }; 435 | 436 | struct NUnion: public NStruct 437 | { 438 | AST_NODE(NUnion) 439 | 440 | NUnion(const NodeList& arguments, const NodeList& members): NStruct(arguments, members) { } 441 | NUnion(NIdentifier* id, const NodeList& arguments, const NodeList& members): NStruct(id, arguments, members) { } 442 | NUnion(const NodeList& arguments, const NodeList& members, const NodeList& customvars): NStruct(arguments, members, customvars) { } 443 | NUnion(NIdentifier* id, const NodeList& arguments, const NodeList& members, const NodeList& customvars): NStruct(id, arguments, members, customvars) { } 444 | }; 445 | 446 | struct NTypedef: public NType 447 | { 448 | AST_NODE(NTypedef) 449 | 450 | NTypedef(Node* type, NIdentifier* name, const NodeList& customvars): NType(name, customvars), type(type) { is_basic = false; } 451 | virtual ~NTypedef() { delete type; } 452 | 453 | Node* type; 454 | }; 455 | 456 | // --------------------------------------------------------- 457 | // Function Nodes 458 | // --------------------------------------------------------- 459 | 460 | struct NFunction: public Node 461 | { 462 | AST_NODE(NFunction) 463 | 464 | NFunction(NType* type, NIdentifier* name, NBlock* body): Node(), type(type), name(name), body(body) { } 465 | NFunction(NType* type, NIdentifier* name, const NodeList& arguments, NBlock* body): Node(), type(type), name(name), arguments(arguments), body(body) { } 466 | ~NFunction() { delete type; delete name; delete_nodelist(arguments); delete body; } 467 | 468 | NType* type; 469 | NIdentifier* name; 470 | NodeList arguments; 471 | NBlock* body; 472 | }; 473 | 474 | // --------------------------------------------------------- 475 | // Expression Nodes 476 | // --------------------------------------------------------- 477 | 478 | struct NCall: public Node 479 | { 480 | AST_NODE(NCall) 481 | 482 | NCall(NIdentifier* name): name(name) { } 483 | NCall(NIdentifier* name, const NodeList& arguments): name(name), arguments(arguments) { } 484 | ~NCall() { delete name; delete_nodelist(arguments); } 485 | 486 | NIdentifier* name; 487 | NodeList arguments; 488 | }; 489 | 490 | struct NCast: public Node 491 | { 492 | AST_NODE(NCast) 493 | 494 | NCast(Node* cast, Node* expression): Node(), cast(cast), expression(expression) { } 495 | 496 | Node* cast; 497 | Node* expression; 498 | }; 499 | 500 | std::string dump_ast(Node* n); 501 | 502 | #endif // AST_H 503 | -------------------------------------------------------------------------------- /btvm/vm/vm.cpp: -------------------------------------------------------------------------------- 1 | #include "vm.h" 2 | #include 3 | 4 | using namespace std; 5 | 6 | #define btv_eq_op() { btv = lbtv; \ 7 | btv->assign(*rbtv); } 8 | 9 | #define btv_eq_lr_op(op) { btv = lbtv; \ 10 | btv->assign(*btv op *rbtv); } 11 | 12 | #define CurrentScope() (this->_scopestack.empty() ? this->_globalscope : this->_scopestack.back()) 13 | #define SetFieldOffset(vmvalue, i) vmvalue->value_offset = vmvalue->m_value[i]->value_offset 14 | 15 | VM::VM(): _ast(NULL), state(VMState::NoState) 16 | { 17 | 18 | } 19 | 20 | VM::~VM() 21 | { 22 | if(!this->_ast) 23 | return; 24 | 25 | delete this->_ast; 26 | this->_ast = NULL; 27 | } 28 | 29 | VMValuePtr VM::execute(const string &file) 30 | { 31 | return this->evaluate(this->readFile(file)); 32 | } 33 | 34 | VMValuePtr VM::evaluate(const string &code) 35 | { 36 | this->parse(code); 37 | 38 | if(!this->_ast || (this->state == VMState::Error)) 39 | return VMValuePtr(); 40 | 41 | return this->interpret(this->_ast); 42 | } 43 | 44 | void VM::parse(const string &code) 45 | { 46 | if(this->_ast) 47 | delete this->_ast; 48 | 49 | this->state = VMState::NoState; 50 | this->allocations.clear(); 51 | VMUnused(code); 52 | } 53 | 54 | void VM::dump(const string &file, const string &astfile) 55 | { 56 | this->parse(this->readFile(file)); 57 | 58 | if(!this->_ast) 59 | return; 60 | 61 | this->writeFile(astfile, dump_ast(this->_ast)); 62 | } 63 | 64 | void VM::loadAST(NBlock *ast) 65 | { 66 | this->_ast = ast; 67 | } 68 | 69 | VMValuePtr VM::interpret(const NodeList &nodelist) 70 | { 71 | VMValuePtr res; 72 | 73 | for(auto it = nodelist.begin(); it != nodelist.end(); it++) 74 | { 75 | res = this->interpret(*it); 76 | 77 | if((this->state == VMState::Error) || (this->state == VMState::Continue) || (this->state == VMState::Break)) 78 | return VMValuePtr(); 79 | if(this->state == VMState::Return) 80 | break; 81 | } 82 | 83 | return res; 84 | } 85 | 86 | VMValuePtr VM::interpret(NConditional *nconditional) 87 | { 88 | ScopeContext(this); 89 | 90 | if(*this->interpret(nconditional->condition)) 91 | return this->interpret(nconditional->true_block); 92 | else if(nconditional->false_block) 93 | return this->interpret(nconditional->false_block); 94 | 95 | return VMValuePtr(); 96 | } 97 | 98 | VMValuePtr VM::interpret(NDoWhile *ndowhile) 99 | { 100 | VMValuePtr vmvalue; 101 | 102 | do 103 | { 104 | ScopeContext(this); 105 | vmvalue = this->interpret(ndowhile->true_block); 106 | 107 | int vms = VMFunctions::state_check(&this->state); 108 | 109 | if(vms == VMState::Continue) 110 | continue; 111 | if(vms == VMState::Break) 112 | break; 113 | if(vms == VMState::Return) 114 | return vmvalue; 115 | } 116 | while(*this->interpret(ndowhile->condition)); 117 | 118 | return VMValuePtr(); 119 | } 120 | 121 | VMValuePtr VM::interpret(NWhile *nwhile) 122 | { 123 | VMValuePtr vmvalue; 124 | 125 | while(*this->interpret(nwhile->condition)) 126 | { 127 | ScopeContext(this); 128 | vmvalue = this->interpret(nwhile->true_block); 129 | 130 | int vms = VMFunctions::state_check(&this->state); 131 | 132 | if(vms == VMState::Continue) 133 | continue; 134 | if(vms == VMState::Break) 135 | break; 136 | if(vms == VMState::Return) 137 | return vmvalue; 138 | } 139 | 140 | return VMValuePtr(); 141 | } 142 | 143 | VMValuePtr VM::interpret(NFor *nfor) 144 | { 145 | VMValuePtr vmvalue; 146 | this->interpret(nfor->counter); 147 | 148 | while(*this->interpret(nfor->condition)) 149 | { 150 | ScopeContext(this); 151 | 152 | vmvalue = this->interpret(nfor->true_block); 153 | this->interpret(nfor->update); 154 | int vms = VMFunctions::state_check(&this->state); 155 | 156 | if(vms == VMState::Continue) 157 | continue; 158 | if(vms == VMState::Break) 159 | break; 160 | if(vms == VMState::Return) 161 | return vmvalue; 162 | } 163 | 164 | return VMValuePtr(); 165 | } 166 | 167 | VMValuePtr VM::interpret(NSwitch *nswitch) 168 | { 169 | VMCaseMap casemap = this->buildCaseMap(nswitch); 170 | auto itcond = casemap.find(*this->interpret(nswitch->expression)); 171 | 172 | if(itcond == casemap.end()) 173 | { 174 | if(!nswitch->defaultcase) 175 | return VMValuePtr(); 176 | 177 | return this->interpret(static_cast(nswitch->defaultcase)->body); 178 | } 179 | 180 | VMValuePtr vmvalue; 181 | 182 | for(auto it = nswitch->cases.begin() + itcond->second; it != nswitch->cases.end(); it++) 183 | { 184 | NCase* ncase = static_cast(*it); 185 | vmvalue = this->interpret(ncase->body); 186 | 187 | int vms = VMFunctions::state_check(&this->state); 188 | 189 | if(vms == VMState::Break) 190 | break; 191 | else if(vms == VMState::Return) 192 | return vmvalue; 193 | } 194 | 195 | return VMValuePtr(); 196 | 197 | } 198 | 199 | VMValuePtr VM::interpret(NCompareOperator *ncompare) 200 | { 201 | if(ncompare->cmp == "==") 202 | return VMValue::copy_value((*this->interpret(ncompare->left) == *this->interpret(ncompare->right))); 203 | else if(ncompare->cmp == "!=") 204 | return VMValue::copy_value((*this->interpret(ncompare->left) != *this->interpret(ncompare->right))); 205 | else if(ncompare->cmp == "<=") 206 | return VMValue::copy_value((*this->interpret(ncompare->left) <= *this->interpret(ncompare->right))); 207 | else if(ncompare->cmp == ">=") 208 | return VMValue::copy_value((*this->interpret(ncompare->left) >= *this->interpret(ncompare->right))); 209 | else if(ncompare->cmp == "<") 210 | return VMValue::copy_value((*this->interpret(ncompare->left) < *this->interpret(ncompare->right))); 211 | else if(ncompare->cmp == ">") 212 | return VMValue::copy_value((*this->interpret(ncompare->left) > *this->interpret(ncompare->right))); 213 | 214 | return this->error("Unknown conditional operator '" + ncompare->cmp + "'"); 215 | } 216 | 217 | VMValuePtr VM::interpret(NUnaryOperator *nunary) 218 | { 219 | VMValuePtr btv = this->interpret(nunary->expression); 220 | 221 | if(!btv->is_scalar()) 222 | return this->error("Cannot use unary operators on '" + btv->type_name() + "' types"); 223 | 224 | if(nunary->op == "++") 225 | return nunary->is_prefix ? VMValue::copy_value(++(*btv)) : VMValue::copy_value((*btv)++); 226 | 227 | if(nunary->op == "--") 228 | return nunary->is_prefix ? VMValue::copy_value(--(*btv)) : VMValue::copy_value((*btv)--); 229 | 230 | if(nunary->op == "!") 231 | return VMValue::copy_value(!(*btv)); 232 | 233 | if(nunary->op == "~") 234 | return VMValue::copy_value(~(*btv)); 235 | 236 | if(nunary->op == "-") 237 | return VMValue::copy_value(-(*btv)); 238 | 239 | return this->error("Unknown unary operator '" + nunary->op + "'"); 240 | } 241 | 242 | VMValuePtr VM::interpret(NBinaryOperator *nbinary) 243 | { 244 | VMValuePtr lbtv = this->interpret(nbinary->left); 245 | VMValuePtr rbtv = this->interpret(nbinary->right); 246 | 247 | if(!VMFunctions::is_type_compatible(lbtv, rbtv)) 248 | return this->error("Cannot use '" + nbinary->op + "' operator with '" + lbtv->type_name() + "' and '" + rbtv->type_name() + "'"); 249 | else if((nbinary->op == "=") && lbtv->is_const()) 250 | return this->error("Could not assign to constant variable '" + lbtv->value_id + "'"); 251 | 252 | VMValuePtr btv; 253 | 254 | if(nbinary->op == "+") 255 | btv = VMValue::copy_value(*lbtv + *rbtv); 256 | else if(nbinary->op == "-") 257 | btv = VMValue::copy_value(*lbtv - *rbtv); 258 | else if(nbinary->op == "*") 259 | btv = VMValue::copy_value(*lbtv * *rbtv); 260 | else if(nbinary->op == "/") 261 | btv = VMValue::copy_value(*lbtv / *rbtv); 262 | else if(nbinary->op == "%") 263 | btv = VMValue::copy_value(*lbtv % *rbtv); 264 | else if(nbinary->op == "&") 265 | btv = VMValue::copy_value(*lbtv & *rbtv); 266 | else if(nbinary->op == "|") 267 | btv = VMValue::copy_value(*lbtv | *rbtv); 268 | else if(nbinary->op == "^") 269 | btv = VMValue::copy_value(*lbtv ^ *rbtv); 270 | else if(nbinary->op == "<<") 271 | btv = VMValue::copy_value(*lbtv << *rbtv); 272 | else if(nbinary->op == ">>") 273 | btv = VMValue::copy_value(*lbtv >> *rbtv); 274 | else if(nbinary->op == "&&") 275 | btv = VMValue::copy_value(*lbtv && *rbtv); 276 | else if(nbinary->op == "||") 277 | btv = VMValue::copy_value(*lbtv || *rbtv); 278 | else if(nbinary->op == "+=") 279 | btv_eq_lr_op(+) 280 | else if(nbinary->op == "-=") 281 | btv_eq_lr_op(-) 282 | else if(nbinary->op == "*=") 283 | btv_eq_lr_op(*) 284 | else if(nbinary->op == "/=") 285 | btv_eq_lr_op(/) 286 | else if(nbinary->op == "^=") 287 | btv_eq_lr_op(^) 288 | else if(nbinary->op == "&=") 289 | btv_eq_lr_op(&) 290 | else if(nbinary->op == "|=") 291 | btv_eq_lr_op(|) 292 | else if(nbinary->op == "<<=") 293 | btv_eq_lr_op(<<) 294 | else if(nbinary->op == ">>=") 295 | btv_eq_lr_op(>>) 296 | else if(nbinary->op == "=") 297 | btv_eq_op() 298 | else 299 | return this->error("Unknown binary operator '" + nbinary->op + "'"); 300 | 301 | return btv; 302 | } 303 | 304 | VMValuePtr VM::interpret(NIndexOperator *nindex) 305 | { 306 | VMValuePtr vmindex = this->interpret(nindex->index); 307 | 308 | if(!vmindex->is_integer()) 309 | return this->error("integer-type expected, '" + vmindex->type_name() + "' given"); 310 | else if(vmindex->is_negative()) 311 | return this->error("Positive integer expected, " + vmindex->to_string() + " given"); 312 | 313 | VMValuePtr lhs = this->interpret(nindex->expression); 314 | return (*lhs)[vmindex->ui_value]; 315 | } 316 | 317 | VMValuePtr VM::interpret(NDotOperator *ndot) 318 | { 319 | if(!node_is(ndot->right, NIdentifier)) 320 | return this->error("Expected NIdentifier, '" + node_typename(ndot->right) + "' given"); 321 | 322 | VMValuePtr vmvalue = this->interpret(ndot->left); 323 | 324 | if(!vmvalue->is_compound()) 325 | return this->error("Cannot use '.' operator on '" + vmvalue->type_name() + "' type"); 326 | 327 | NIdentifier* nid = static_cast(ndot->right); 328 | 329 | if(node_is_compound(vmvalue->value_typedef)) 330 | return (*vmvalue)[nid->value]; 331 | 332 | return this->error("Cannot access '" + nid->value + "' from '" + vmvalue->value_id + "' of type '" + node_typename(vmvalue->value_typedef) + "'"); 333 | } 334 | 335 | VMValuePtr VM::interpret(NReturn *nreturn) 336 | { 337 | this->state = VMState::Return; 338 | return this->interpret(nreturn->block); 339 | } 340 | 341 | VMValuePtr VM::interpret(NCast *ncast) 342 | { 343 | Node* ndecl = this->declaration(ncast->cast); 344 | VMValuePtr vmvalue = this->interpret(ncast->expression); 345 | 346 | if(!VMFunctions::type_cast(vmvalue, ndecl)) 347 | return this->error("Cannot convert '" + vmvalue->type_name() + "' to '" + node_typename(ndecl) + "'"); 348 | 349 | return vmvalue; 350 | } 351 | 352 | VMValuePtr VM::interpret(NSizeOf *nsizeof) 353 | { 354 | return VMValue::allocate_literal(this->sizeOf(nsizeof->expression)); 355 | } 356 | 357 | VMValuePtr VM::interpret(NEnum *nenum) 358 | { 359 | if(is_anonymous_identifier(nenum->name)) 360 | { 361 | VMScope& vmscope = CurrentScope(); 362 | this->allocEnum(nenum, [&vmscope](const VMValuePtr& vmvalue) { vmscope.variables[vmvalue->value_id] = VMValue::copy_value(*vmvalue); }); 363 | } 364 | else 365 | this->declare(nenum); 366 | 367 | return VMValuePtr(); 368 | } 369 | 370 | VMValuePtr VM::interpret(Node *node) 371 | { 372 | if(this->state == VMState::Error) 373 | return VMValuePtr(); 374 | 375 | if(node_is(node, NBlock)) 376 | return this->interpret(static_cast(node)->statements); 377 | else if(node_is(node, NEnum)) 378 | return this->interpret(static_cast(node)); 379 | else if(node_inherits(node, NType) || node_is(node, NFunction)) 380 | this->declare(node); 381 | else if(node_is(node, NVariable)) 382 | this->declareVariables(static_cast(node)); 383 | else if(node_is(node, NIdentifier)) 384 | return this->variable(static_cast(node)); 385 | else if(node_is(node, NCast)) 386 | return this->interpret(static_cast(node)); 387 | else if(node_is(node, NReturn)) 388 | return this->interpret(static_cast(node)); 389 | else if(node_is(node, NCompareOperator)) 390 | return this->interpret(static_cast(node)); 391 | else if(node_is(node, NUnaryOperator)) 392 | return this->interpret(static_cast(node)); 393 | else if(node_is(node, NBinaryOperator)) 394 | return this->interpret(static_cast(node)); 395 | else if(node_is(node, NIndexOperator)) 396 | return this->interpret(static_cast(node)); 397 | else if(node_is(node, NDotOperator)) 398 | return this->interpret(static_cast(node)); 399 | else if(node_is(node, NBoolean)) 400 | return VMValue::allocate_literal(static_cast(node)->value, node); 401 | else if(node_is(node, NInteger)) 402 | return VMValue::allocate_literal(static_cast(node)->value, node); 403 | else if(node_is(node, NReal)) 404 | return VMValue::allocate_literal(static_cast(node)->value, node); 405 | else if(node_is(node, NString)) 406 | return VMValue::allocate_literal(static_cast(node)->value, node); 407 | else if(node_is(node, NDoWhile)) 408 | return this->interpret(static_cast(node)); 409 | else if(node_is(node, NWhile)) 410 | return this->interpret(static_cast(node)); 411 | else if(node_is(node, NFor)) 412 | return this->interpret(static_cast(node)); 413 | else if(node_is(node, NSwitch)) 414 | return this->interpret(static_cast(node)); 415 | else if(node_is(node, NConditional)) 416 | return this->interpret(static_cast(node)); 417 | else if(node_is(node, NSizeOf)) 418 | return this->interpret(static_cast(node)); 419 | else if(node_is(node, NCall)) 420 | return this->call(static_cast(node)); 421 | else if(node_is(node, NVMState)) 422 | this->state = static_cast(node)->state; 423 | else 424 | throw std::runtime_error("Cannot interpret '" + node_typename(node) + "'"); 425 | 426 | return VMValuePtr(); 427 | } 428 | 429 | void VM::declare(Node *node) 430 | { 431 | NIdentifier* nid = NULL; 432 | Node* ntype = node; 433 | 434 | if(node_is(node, NTypedef)) 435 | { 436 | NTypedef* ntypedef = static_cast(node); 437 | 438 | if(node_is_compound(ntypedef->type)) 439 | this->declare(ntypedef->type); 440 | 441 | nid = ntypedef->name; 442 | ntype = ntypedef->type; 443 | } 444 | else if(node_inherits(node, NType)) 445 | { 446 | NType* ntype = static_cast(node); 447 | 448 | if(ntype->is_basic) 449 | throw std::runtime_error("Trying to declare '" + ntype->name->value + "'"); 450 | 451 | nid = ntype->name; 452 | } 453 | else if(node_is(node, NFunction)) 454 | nid = static_cast(node)->name; 455 | 456 | if(!nid) 457 | { 458 | throw std::runtime_error("Cannot declare '" + node_typename(ntype) + "'"); 459 | return; 460 | } 461 | 462 | if(is_anonymous_identifier(nid)) // Skip anonymous IDs 463 | return; 464 | 465 | Node* ndecl = this->isDeclared(nid); 466 | 467 | if(ndecl) 468 | { 469 | this->error("'" + nid->value + "' was declared as '" + node_typename(ntype) + "'"); 470 | return; 471 | } 472 | 473 | VMScope& vmscope = CurrentScope(); 474 | vmscope.declarations[nid->value] = ntype; 475 | } 476 | 477 | void VM::declareVariables(NVariable *nvar) 478 | { 479 | this->declareVariable(nvar); 480 | 481 | std::for_each(nvar->names.begin(), nvar->names.end(), [this, nvar](Node* n) { 482 | NVariable* nsubvar = static_cast(n); 483 | 484 | nsubvar->type = nvar->type; // FIXME: Borrow type 485 | nsubvar->is_local = nvar->is_local; 486 | nsubvar->is_const = nvar->is_const; 487 | 488 | this->declareVariable(nsubvar); 489 | nsubvar->type = NULL; 490 | }); 491 | } 492 | 493 | void VM::declareVariable(NVariable *nvar) 494 | { 495 | VMValuePtr vmvar = VMValue::allocate(nvar->name->value); 496 | vmvar->value_typeid = VMFunctions::node_typeid(nvar->type); 497 | 498 | if(!this->_declarationstack.empty()) 499 | { 500 | VMValuePtr vmvalue = this->_declarationstack.back(); 501 | vmvalue->m_value.push_back(vmvar); 502 | this->allocVariable(vmvar, nvar); 503 | return; 504 | } 505 | 506 | VMScope& scope = CurrentScope(); 507 | auto it = scope.variables.find(vmvar->value_id); 508 | 509 | if(it != scope.variables.end()) 510 | { 511 | this->error("Shadowing variable '" + vmvar->value_id + "'"); 512 | return; 513 | } 514 | 515 | scope.variables[vmvar->value_id] = vmvar; 516 | this->allocVariable(vmvar, nvar); 517 | } 518 | 519 | void VM::allocType(const VMValuePtr& vmvar, Node *node, Node *nsize, const NodeList& nconstructor) 520 | { 521 | Node* ndecl = node_is(node, NType) ? this->declaration(node) : node; 522 | 523 | if(nsize) 524 | { 525 | VMValuePtr vmsize = this->interpret(nsize); 526 | 527 | if(!this->isSizeValid(vmsize)) 528 | return; 529 | 530 | if(!node_is(ndecl, NCharType)) 531 | { 532 | vmvar->allocate_array(vmsize->ui_value, ndecl); 533 | 534 | for(uint64_t i = 0; i < vmsize->ui_value; i++) 535 | { 536 | VMValuePtr vmelement = VMValue::allocate(); 537 | vmvar->m_value.push_back(vmelement); 538 | this->allocType(vmelement, ndecl); 539 | } 540 | } 541 | else 542 | vmvar->allocate_string(vmsize->ui_value, ndecl); 543 | 544 | return; 545 | } 546 | 547 | if(node_is(ndecl, NStruct) || node_is(ndecl, NUnion)) 548 | { 549 | NCompoundType* ncompound = static_cast(ndecl); 550 | 551 | if(node_is(ndecl, NUnion)) 552 | vmvar->allocate_type(VMValueType::Union, ndecl); 553 | else 554 | vmvar->allocate_type(VMValueType::Struct, ndecl); 555 | 556 | if(ncompound->arguments.size() != nconstructor.size()) 557 | { 558 | this->argumentError(ncompound->name, ncompound->arguments, nconstructor); 559 | return; 560 | } 561 | 562 | this->_declarationstack.push_back(vmvar); 563 | 564 | if(!this->pushScope(ncompound->name, ncompound->arguments, nconstructor)) 565 | return; 566 | 567 | this->interpret(ncompound->members); 568 | 569 | this->_scopestack.pop_back(); 570 | this->_declarationstack.pop_back(); 571 | 572 | if(node_is(ndecl, NUnion)) 573 | this->readValue(NULL, this->sizeOf(vmvar), true); // Seek away from union 574 | } 575 | else if(node_is(ndecl, NEnum)) 576 | { 577 | NEnum* nenum = static_cast(ndecl); 578 | vmvar->allocate_type(VMValueType::Enum, ndecl); 579 | this->allocEnum(nenum, [vmvar](const VMValuePtr& vmvalue) { vmvar->m_value.push_back(VMValue::copy_value(*vmvalue)); }); 580 | } 581 | else if(node_inherits(ndecl, NScalarType)) 582 | { 583 | NScalarType* nscalar = static_cast(ndecl); 584 | vmvar->allocate_scalar(nscalar->bits, nscalar->is_signed, nscalar->is_fp, ndecl); 585 | } 586 | else if(node_is(ndecl, NStringType)) 587 | vmvar->allocate_string(0, ndecl); 588 | else if(node_is(ndecl, NBooleanType)) 589 | vmvar->allocate_boolean(ndecl); 590 | else 591 | throw std::runtime_error("Unknown type: '" + node_typename(ndecl) + "'"); 592 | } 593 | 594 | void VM::allocVariable(const VMValuePtr& vmvar, NVariable *nvar) 595 | { 596 | if(nvar->bits) 597 | vmvar->value_bits = *this->interpret(nvar->bits)->value_ref(); 598 | 599 | if(nvar->is_const) 600 | vmvar->value_flags |= VMValueFlags::Const; 601 | 602 | if(nvar->is_local) 603 | vmvar->value_flags |= VMValueFlags::Local; 604 | 605 | if(vmvar->is_template()) 606 | vmvar->value_offset = this->currentOffset(); 607 | 608 | if(vmvar->value_fgcolor == ColorInvalid) 609 | vmvar->value_fgcolor= this->currentFgColor(); 610 | 611 | if(vmvar->value_bgcolor == ColorInvalid) 612 | vmvar->value_bgcolor= this->currentBgColor(); 613 | 614 | this->applyCustomVariables(vmvar, nvar); 615 | this->allocType(vmvar, nvar->type, this->arraySize(nvar), nvar->constructor); 616 | 617 | if(!nvar->is_const && !nvar->is_local) 618 | { 619 | this->readValue(vmvar, this->_declarationstack.empty() || !this->_declarationstack.back()->is_union()); 620 | 621 | if(this->_declarationstack.empty()) 622 | this->allocations.push_back(vmvar); 623 | } 624 | else if(nvar->value) 625 | { 626 | VMValuePtr vmvalue = this->interpret(nvar->value); 627 | 628 | if(!VMFunctions::is_type_compatible(vmvar, vmvalue)) 629 | { 630 | this->error("'" + vmvar->value_id + "': cannot assign '" + vmvalue->type_name() + "' to '" + vmvar->type_name() + "'"); 631 | return; 632 | } 633 | 634 | vmvar->assign(*vmvalue); 635 | } 636 | } 637 | 638 | void VM::allocEnum(NEnum *nenum, std::function cb) 639 | { 640 | VMValuePtr vmenumval; 641 | 642 | for(auto it = nenum->members.begin(); it != nenum->members.end(); it++) 643 | { 644 | if(!node_is(*it, NEnumValue)) 645 | { 646 | this->error("Unexpected enum-value of type '" + node_typename(*it) + "'"); 647 | return; 648 | } 649 | 650 | NEnumValue* nenumval = static_cast(*it); 651 | 652 | if(nenumval->value) 653 | vmenumval = this->interpret(nenumval->value); 654 | else 655 | { 656 | if(!vmenumval) 657 | { 658 | vmenumval = VMValue::allocate(); 659 | this->allocType(vmenumval, nenum->type); 660 | } 661 | else 662 | (*vmenumval)++; 663 | } 664 | 665 | vmenumval->value_flags |= VMValueFlags::Const; 666 | vmenumval->value_typedef = nenum->type; 667 | vmenumval->value_id = nenumval->name->value; 668 | cb(vmenumval); 669 | } 670 | } 671 | 672 | VMValuePtr VM::variable(NIdentifier *nid) 673 | { 674 | VMValuePtr vmvalue; 675 | 676 | if(!this->_declarationstack.empty()) 677 | { 678 | for(auto it = this->_declarationstack.rbegin(); it != this->_declarationstack.rend(); it++) 679 | { 680 | vmvalue = (*it)->is_member(nid->value); 681 | 682 | if(vmvalue) 683 | break; 684 | } 685 | } 686 | 687 | for(auto it = this->allocations.rbegin(); it != this->allocations.rend(); it++) 688 | { 689 | if((*it)->value_id == nid->value) 690 | { 691 | vmvalue = *it; 692 | break; 693 | } 694 | } 695 | 696 | if(!vmvalue) 697 | { 698 | vmvalue = this->symbol(nid, [](const VMScope& vmscope, NIdentifier* nid) -> VMValuePtr { 699 | auto it = vmscope.variables.find(nid->value); 700 | return it != vmscope.variables.end() ? it->second : NULL; 701 | }); 702 | } 703 | 704 | if(!vmvalue) 705 | return this->error("Undeclared variable '" + nid->value + "'"); 706 | 707 | return vmvalue; 708 | } 709 | 710 | Node *VM::declaration(Node *node) 711 | { 712 | if(node_is(node, NType)) 713 | { 714 | NType* ntype = static_cast(node); 715 | 716 | if(ntype->is_basic) 717 | return node; 718 | 719 | return this->declaration(ntype->name); 720 | } 721 | else if(node_inherits(node, NIdentifier)) 722 | { 723 | NIdentifier* nid = static_cast(node); 724 | Node* ndecl = this->isDeclared(nid); 725 | 726 | if(!ndecl) 727 | this->error("'" + nid->value + "' is undeclared"); 728 | 729 | return ndecl; 730 | } 731 | else if(node_inherits(node, NType)) 732 | return node; 733 | 734 | this->error("'" + node_typename(node) + "' unknown declaration type"); 735 | return NULL; 736 | } 737 | 738 | std::string VM::readFile(const string &file) const 739 | { 740 | FILE *fp = std::fopen(file.c_str(), "rb"); 741 | 742 | string s; 743 | std::fseek(fp, 0, SEEK_END); 744 | 745 | s.resize(std::ftell(fp)); 746 | 747 | std::rewind(fp); 748 | std::fread(&s[0], 1, s.size(), fp); 749 | std::fclose(fp); 750 | 751 | return s; 752 | } 753 | 754 | void VM::writeFile(const string &file, const string &data) const 755 | { 756 | FILE *fp = std::fopen(file.c_str(), "wb"); 757 | std::fwrite(data.c_str(), sizeof(string::traits_type), data.size(), fp); 758 | std::fclose(fp); 759 | } 760 | 761 | void VM::readValue(const VMValuePtr &vmvar, bool seek) 762 | { 763 | if(vmvar->is_array()) 764 | { 765 | for(auto it = vmvar->m_value.begin(); it != vmvar->m_value.end(); it++) 766 | this->readValue(*it, seek); 767 | } 768 | else if(vmvar->is_readable()) 769 | this->readValue(vmvar, this->sizeOf(vmvar), seek); 770 | } 771 | 772 | void VM::applyCustomVariables(const VMValuePtr &vmvar, NVariable *nvar) 773 | { 774 | for(auto it = nvar->custom_vars.begin(); it != nvar->custom_vars.end(); it++) 775 | { 776 | if(!node_is(*it, NCustomVariable)) 777 | { 778 | this->error("Expected 'NCustomVariable', got '" + node_typename(*it)); 779 | return; 780 | } 781 | 782 | NCustomVariable* ncustomvar = static_cast(*it); 783 | 784 | if(ncustomvar->action == "fgcolor") 785 | { 786 | if(!node_is(ncustomvar->value, NIdentifier)) 787 | { 788 | this->error("Expected 'NIdentifier', got '" + node_typename(ncustomvar->value) + "'"); 789 | return; 790 | } 791 | 792 | vmvar->value_fgcolor = this->color(static_cast(ncustomvar->value)->value); 793 | } 794 | else if(ncustomvar->action == "bgcolor") 795 | { 796 | if(!node_is(ncustomvar->value, NIdentifier)) 797 | { 798 | this->error("Expected 'NIdentifier', got '" + node_typename(ncustomvar->value) + "'"); 799 | return; 800 | } 801 | 802 | vmvar->value_bgcolor = this->color(static_cast(ncustomvar->value)->value); 803 | } 804 | else if(ncustomvar->action == "comment") 805 | { 806 | if(node_is(ncustomvar->value, NString)) 807 | vmvar->value_comment = static_cast(ncustomvar->value)->value; 808 | } 809 | } 810 | } 811 | 812 | bool VM::pushScope(NIdentifier* nid, const NodeList& funcargs, const NodeList& callargs) 813 | { 814 | VMVariables locals; // Build local variable stack 815 | 816 | for(size_t i = 0; i < callargs.size(); i++) 817 | { 818 | NArgument* narg = static_cast(funcargs[i]); 819 | VMValuePtr vmarg = this->interpret(callargs[i]); 820 | 821 | if(!narg->by_reference) 822 | vmarg = VMValue::copy_value(*vmarg); // Copy value 823 | 824 | if(!VMFunctions::type_cast(vmarg, this->declaration(narg->type))) 825 | { 826 | this->error("'" + nid->value + "': " + 827 | "cannot convert argument " + std::to_string(i) + " from '" + vmarg->type_name() + 828 | "' to '" + node_typename(narg->type) + "'"); 829 | 830 | return false; 831 | } 832 | 833 | vmarg->value_id = narg->name->value; 834 | locals[narg->name->value] = vmarg; 835 | } 836 | 837 | this->_scopestack.push_back(VMScope(locals)); 838 | return true; 839 | } 840 | 841 | VM::VMCaseMap VM::buildCaseMap(NSwitch *nswitch) 842 | { 843 | auto it = this->_switchmap.find(nswitch); 844 | 845 | if(it != this->_switchmap.end()) 846 | return it->second; 847 | 848 | uint64_t i = 0; 849 | VMCaseMap casemap; 850 | 851 | for(auto it = nswitch->cases.begin(); it != nswitch->cases.end(); it++) 852 | { 853 | if(!node_is(*it, NCase)) 854 | { 855 | this->error("Expected NCase, got '" + node_typename(*it) + "'"); 856 | return VMCaseMap(); 857 | } 858 | 859 | NCase* ncase = static_cast(*it); 860 | 861 | if(!ncase->value) 862 | { 863 | nswitch->defaultcase = ncase; 864 | continue; 865 | } 866 | 867 | casemap[*this->interpret(ncase->value)] = i++; 868 | } 869 | 870 | this->_switchmap[nswitch] = casemap; 871 | return casemap; 872 | } 873 | 874 | int64_t VM::getBits(const VMValuePtr &vmvalue) 875 | { 876 | return vmvalue->value_bits; 877 | } 878 | 879 | int64_t VM::getBits(Node *n) 880 | { 881 | if(!node_is(n, NVariable)) 882 | throw std::runtime_error("Cannot get bit size from '" + node_typename(n) + "'"); 883 | 884 | NVariable* nvar = static_cast(n); 885 | 886 | if(nvar->bits) 887 | return *this->interpret(nvar->bits)->value_ref(); 888 | 889 | return -1; 890 | } 891 | 892 | VMValuePtr VM::call(NCall *ncall) 893 | { 894 | if(this->isVMFunction(ncall->name)) 895 | return this->callVM(ncall); 896 | 897 | Node* ndecl = this->declaration(ncall->name); 898 | 899 | if(!ndecl) 900 | return this->error("Function '" + ncall->name->value + "' is not declared"); 901 | 902 | if(!node_is(ndecl, NFunction)) 903 | return this->error("Trying to call a '" + node_typename(ndecl) + "' type"); 904 | 905 | NFunction* nfunc = static_cast(ndecl); 906 | 907 | if(nfunc->arguments.size() != ncall->arguments.size()) 908 | return this->argumentError(nfunc->name, ncall->arguments, nfunc->arguments); 909 | 910 | if(!this->pushScope(nfunc->name, nfunc->arguments, ncall->arguments)) 911 | return VMValuePtr(); 912 | 913 | VMValuePtr res = this->interpret(nfunc->body); 914 | this->_scopestack.pop_back(); 915 | this->state = VMState::NoState; // Reset VM's state 916 | return res; 917 | } 918 | 919 | 920 | Node *VM::isDeclared(NIdentifier* nid) const 921 | { 922 | return this->symbol(nid, [](const VMScope& vmscope, NIdentifier* nid) -> Node* { 923 | auto it = vmscope.declarations.find(nid->value); 924 | return it != vmscope.declarations.end() ? it->second : NULL; 925 | }); 926 | } 927 | 928 | bool VM::isLocal(Node *node) const 929 | { 930 | if(!node_is(node, NVariable)) 931 | return false; 932 | 933 | NVariable* nvar = static_cast(node); 934 | return nvar->is_const || nvar->is_local; 935 | } 936 | 937 | bool VM::isLocal(const VMValuePtr &vmvalue) const 938 | { 939 | return vmvalue->is_local() || vmvalue->is_const(); 940 | } 941 | 942 | bool VM::isVMFunction(NIdentifier *id) const 943 | { 944 | return this->functions.find(id->value) != this->functions.cend(); 945 | } 946 | 947 | VMValuePtr VM::error(const string &msg) 948 | { 949 | cout << msg << endl; 950 | 951 | this->state = VMState::Error; 952 | this->_globalscope.variables.clear(); 953 | this->_globalscope.declarations.clear(); 954 | this->_scopestack.clear(); 955 | return VMValuePtr(); 956 | } 957 | 958 | VMValuePtr VM::argumentError(NCall *ncall, size_t expected) 959 | { 960 | return this->error("'" + ncall->name->value + "' " + "expects " + std::to_string(expected) + " arguments, " + 961 | std::to_string(ncall->arguments.size()) + " given"); 962 | } 963 | 964 | VMValuePtr VM::argumentError(NIdentifier* nid, const NodeList& given, const NodeList& expected) 965 | { 966 | return this->error("'" + nid->value + "' " + "expects " + std::to_string(expected.size()) + " arguments, " + 967 | std::to_string(given.size()) + " given"); 968 | } 969 | 970 | VMValuePtr VM::typeError(Node *n, const string &expected) 971 | { 972 | return this->error("Expected '" + expected + "', '" + node_typename(n) + "' given"); 973 | } 974 | 975 | VMValuePtr VM::typeError(const VMValuePtr &vmvalue, const string &expected) 976 | { 977 | return this->error("Expected '" + expected + "', '" + vmvalue->type_name() + "' given"); 978 | } 979 | 980 | void VM::syntaxError(const string &token, unsigned int line) 981 | { 982 | this->error("Syntax error near '" + token + "' at line " + std::to_string(line)); 983 | } 984 | 985 | bool VM::isSizeValid(const VMValuePtr &vmvalue) 986 | { 987 | if(!vmvalue->is_integer() || vmvalue->is_negative()) 988 | { 989 | if(!vmvalue->is_integer()) 990 | this->error("Expected integer-type, '" + vmvalue->type_name() + "' given"); 991 | else 992 | this->error("Array size must be positive, " + std::to_string(vmvalue->si_value) + " given"); 993 | 994 | return false; 995 | } 996 | 997 | return true; 998 | } 999 | 1000 | Node *VM::arraySize(NVariable *nvar) 1001 | { 1002 | Node* ndecl = this->declaration(nvar->type); 1003 | 1004 | if(node_inherits(ndecl, NType)) 1005 | { 1006 | NType* ntype = static_cast(ndecl); 1007 | 1008 | if(ntype->size) 1009 | return ntype->size; 1010 | } 1011 | 1012 | return nvar->size; 1013 | } 1014 | 1015 | int64_t VM::sizeOf(Node *node) 1016 | { 1017 | if(node_inherits(node, NBasicType)) 1018 | return static_cast(node)->bits / PLATFORM_BITS; 1019 | else if(node_is(node, NType)) 1020 | return this->sizeOf(this->declaration(node)); 1021 | else if(node_is(node, NIdentifier)) 1022 | return this->sizeOf(static_cast(node)); 1023 | else if(node_is(node, NVariable)) 1024 | return this->sizeOf(static_cast(node)); 1025 | else if(node_is(node, NEnum)) 1026 | return this->sizeOf(static_cast(node)->type); 1027 | else if(node_is(node, NBlock)) 1028 | return this->sizeOf(static_cast(node)->statements); 1029 | else if(node_is(node, NStruct)) 1030 | return this->compoundSize(static_cast(node)->members); 1031 | else if(node_is(node, NUnion)) 1032 | return this->unionSize(static_cast(node)->members); 1033 | 1034 | return this->sizeOf(this->interpret(node)); 1035 | } 1036 | 1037 | int64_t VM::sizeOf(NVariable *nvar) 1038 | { 1039 | if(nvar->size) 1040 | { 1041 | VMValuePtr vmsize = this->interpret(nvar->size); 1042 | 1043 | if(!this->isSizeValid(vmsize)) 1044 | return 0; 1045 | 1046 | return this->sizeOf(nvar->type) * vmsize->ui_value; 1047 | } 1048 | 1049 | return this->sizeOf(nvar->type); 1050 | } 1051 | 1052 | int64_t VM::sizeOf(const VMValuePtr &vmvalue) 1053 | { 1054 | if(vmvalue->is_string()) 1055 | return vmvalue->s_value.empty() ? 0 : vmvalue->s_value.size() - 1; 1056 | 1057 | if(vmvalue->is_array()) 1058 | { 1059 | if(!vmvalue->m_value.capacity()) 1060 | return 0; 1061 | 1062 | return this->sizeOf(vmvalue->m_value.front()) * vmvalue->m_value.capacity(); 1063 | } 1064 | 1065 | if(node_is_compound(vmvalue->value_typedef)) 1066 | { 1067 | if(node_is(vmvalue->value_typedef, NStruct)) 1068 | return this->compoundSize(vmvalue->m_value); 1069 | else if(node_is(vmvalue->value_typedef, NUnion)) 1070 | return this->unionSize(vmvalue->m_value); 1071 | 1072 | return this->sizeOf(vmvalue->value_typedef); 1073 | } 1074 | 1075 | switch(vmvalue->value_type) 1076 | { 1077 | case VMValueType::u8: 1078 | case VMValueType::s8: 1079 | case VMValueType::Bool: 1080 | return 1; 1081 | 1082 | case VMValueType::u16: 1083 | case VMValueType::s16: 1084 | return 2; 1085 | 1086 | case VMValueType::u32: 1087 | case VMValueType::s32: 1088 | case VMValueType::Float: 1089 | return 4; 1090 | 1091 | case VMValueType::u64: 1092 | case VMValueType::s64: 1093 | case VMValueType::Double: 1094 | return 8; 1095 | 1096 | default: 1097 | break; 1098 | } 1099 | 1100 | this->error("Cannot get size of value '" + vmvalue->type_name() + "'"); 1101 | return 0; 1102 | } 1103 | 1104 | int64_t VM::sizeOf(NIdentifier *nid) 1105 | { 1106 | Node* ndecl = this->isDeclared(nid); 1107 | 1108 | if(ndecl) 1109 | return this->sizeOf(ndecl); 1110 | 1111 | return this->sizeOf(this->variable(nid)); 1112 | } 1113 | 1114 | VMValuePtr VM::callVM(NCall *ncall) 1115 | { 1116 | VMFunction vmfunction = this->functions[ncall->name->value]; 1117 | return vmfunction(this, ncall); 1118 | } 1119 | -------------------------------------------------------------------------------- /btvm/vm/vm.h: -------------------------------------------------------------------------------- 1 | #ifndef VM_H 2 | #define VM_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include "ast.h" 10 | #include "vm_functions.h" 11 | 12 | #define ScopeContext(x) VM::VMScopeContext __scope__(x) 13 | 14 | class VM 15 | { 16 | protected: 17 | typedef std::function VMFunction; 18 | typedef std::unordered_map VMVariables; 19 | typedef std::unordered_map VMDeclarations; 20 | typedef std::unordered_map VMFunctionsMap; 21 | 22 | private: 23 | struct VMScope { 24 | VMScope() { } 25 | VMScope(VMVariables v): variables(v) { } 26 | 27 | VMVariables variables; 28 | VMDeclarations declarations; 29 | }; 30 | 31 | struct VMScopeContext { 32 | VMScopeContext(VM* vm): _vm(vm) { this->_vm->_scopestack.push_back(VMScope()); } 33 | ~VMScopeContext() { this->_vm->_scopestack.pop_back(); } 34 | 35 | private: 36 | VM* _vm; 37 | }; 38 | 39 | private: 40 | typedef std::unordered_map VMCaseMap; 41 | typedef std::unordered_map VMSwitchMap; 42 | 43 | protected: 44 | typedef std::deque VMScopeStack; 45 | typedef std::deque VMDeclarationStack; 46 | 47 | public: 48 | VM(); 49 | ~VM(); 50 | VMValuePtr execute(const std::string& file); 51 | VMValuePtr evaluate(const std::string& code); 52 | virtual void parse(const std::string& code); 53 | virtual uint32_t color(const std::string& color) const = 0; 54 | void dump(const std::string& file, const std::string& astfile); 55 | VMValuePtr interpret(Node* node); 56 | void loadAST(NBlock* _ast); 57 | 58 | private: 59 | VMValuePtr interpret(const NodeList& nodelist); 60 | VMValuePtr interpret(NConditional* nconditional); 61 | VMValuePtr interpret(NDoWhile* ndowhile); 62 | VMValuePtr interpret(NWhile* nwhile); 63 | VMValuePtr interpret(NFor* nfor); 64 | VMValuePtr interpret(NSwitch* nswitch); 65 | VMValuePtr interpret(NCompareOperator* ncompare); 66 | VMValuePtr interpret(NUnaryOperator* nunary); 67 | VMValuePtr interpret(NBinaryOperator* nbinary); 68 | VMValuePtr interpret(NIndexOperator* nindex); 69 | VMValuePtr interpret(NDotOperator* ndot); 70 | VMValuePtr interpret(NReturn* nreturn); 71 | VMValuePtr interpret(NCast* ncast); 72 | VMValuePtr interpret(NSizeOf* nsizeof); 73 | VMValuePtr interpret(NEnum* nenum); 74 | void declareVariables(NVariable* nvar); 75 | void declareVariable(NVariable* nvar); 76 | VMValuePtr call(NCall* ncall); 77 | VMValuePtr callVM(NCall* ncall); 78 | void allocType(const VMValuePtr& vmvar, Node *node, Node* nsize = NULL, const NodeList& nconstructor = NodeList()); 79 | void allocVariable(const VMValuePtr &vmvar, NVariable* nvar); 80 | void allocEnum(NEnum* nenum, std::function cb); 81 | VMValuePtr variable(NIdentifier* id); 82 | Node* arraySize(NVariable* nvar); 83 | Node* declaration(Node* node); 84 | Node* isDeclared(NIdentifier *nid) const; 85 | bool isLocal(Node* node) const; 86 | bool isLocal(const VMValuePtr& vmvalue) const; 87 | bool isSizeValid(const VMValuePtr& vmvalue); 88 | bool isVMFunction(NIdentifier* id) const; 89 | bool pushScope(NIdentifier *nid, const NodeList &funcargs, const NodeList &callargs); 90 | VMCaseMap buildCaseMap(NSwitch* nswitch); 91 | int64_t getBits(const VMValuePtr& vmvalue); 92 | int64_t getBits(Node *n); 93 | std::string readFile(const std::string& file) const; 94 | void writeFile(const std::string& file, const std::string& data) const; 95 | void readValue(const VMValuePtr& vmvar, bool seek); 96 | void applyCustomVariables(const VMValuePtr& vmvar, NVariable* nvar); 97 | 98 | public: // Error management 99 | virtual VMValuePtr error(const std::string& msg); 100 | VMValuePtr argumentError(NCall* ncall, size_t expected); 101 | VMValuePtr argumentError(NIdentifier* nid, const NodeList &given, const NodeList &expected); 102 | VMValuePtr typeError(Node* n, const std::string& expected); 103 | VMValuePtr typeError(const VMValuePtr& vmvalue, const std::string& expected); 104 | void syntaxError(const std::string& token, unsigned int line); 105 | 106 | protected: 107 | virtual uint64_t currentOffset() const = 0; 108 | virtual uint32_t currentFgColor() const = 0; 109 | virtual uint32_t currentBgColor() const = 0; 110 | virtual void readValue(const VMValuePtr& vmvar, uint64_t size, bool seek) = 0; 111 | void declare(Node* node); 112 | int64_t sizeOf(const VMValuePtr& vmvalue); 113 | int64_t sizeOf(NIdentifier* nid); 114 | int64_t sizeOf(NVariable* nvar); 115 | int64_t sizeOf(Node* node); 116 | 117 | private: 118 | template T symbol(NIdentifier* nid, std::function cb) const; 119 | template int64_t unionSize(const std::vector &v); 120 | template int64_t compoundSize(const std::vector &v); 121 | template int64_t sizeOf(const std::vector &v); 122 | 123 | private: 124 | VMSwitchMap _switchmap; 125 | VMDeclarationStack _declarationstack; 126 | VMScopeStack _scopestack; 127 | VMScope _globalscope; 128 | NBlock* _ast; 129 | 130 | protected: 131 | std::vector allocations; 132 | VMFunctionsMap functions; 133 | int state; 134 | }; 135 | 136 | template T VM::symbol(NIdentifier *nid, std::function cb) const 137 | { 138 | T symbol; 139 | 140 | for(auto it = this->_scopestack.rbegin(); it != this->_scopestack.rend(); it++) // Loop through parent scopes 141 | { 142 | symbol = cb(*it, nid); 143 | 144 | if(!symbol) 145 | continue; 146 | 147 | return symbol; 148 | } 149 | 150 | return cb(this->_globalscope, nid); // Try globals 151 | } 152 | 153 | template int64_t VM::unionSize(const std::vector &v) 154 | { 155 | int64_t maxsize = 0; 156 | 157 | for(auto it = v.begin(); it != v.end(); it++) 158 | maxsize = std::max(maxsize, this->sizeOf(*it)); 159 | 160 | return maxsize; 161 | } 162 | 163 | template int64_t VM::compoundSize(const std::vector &v) 164 | { 165 | uint64_t totbits = 0, bftotsize = 0, boundarybits = 0; 166 | 167 | for(auto it = v.begin(); it != v.end(); it++) 168 | { 169 | if(this->isLocal(*it)) 170 | continue; 171 | 172 | uint64_t mbits = this->sizeOf(*it) * PLATFORM_BITS; 173 | boundarybits = std::max(mbits, boundarybits); 174 | int64_t bits = this->getBits(*it); 175 | 176 | if(bits > 0) // TODO: Handle bits == 0 177 | { 178 | totbits += bits; 179 | bftotsize += bits; 180 | continue; 181 | } 182 | 183 | totbits += mbits; 184 | 185 | if(bftotsize) 186 | totbits += (boundarybits - bftotsize); 187 | 188 | bftotsize = 0; 189 | } 190 | 191 | if(bftotsize) 192 | totbits += (boundarybits - bftotsize); 193 | 194 | return totbits / PLATFORM_BITS; 195 | } 196 | 197 | template int64_t VM::sizeOf(const std::vector &v) 198 | { 199 | int64_t size = 0; 200 | 201 | for(auto it = v.begin(); it != v.end(); it++) 202 | size += this->sizeOf(*it); 203 | 204 | return size; 205 | } 206 | 207 | #endif // VM_H 208 | -------------------------------------------------------------------------------- /btvm/vm/vm_functions.cpp: -------------------------------------------------------------------------------- 1 | #include "vm_functions.h" 2 | #include 3 | #include 4 | 5 | namespace VMFunctions { 6 | 7 | static VMValuePtr get_arg(const ValueList& args, size_t idx) 8 | { 9 | if(idx >= args.size()) 10 | return VMValuePtr(); 11 | 12 | return args[idx]; 13 | } 14 | 15 | static VMValueType::VMType literal_type(NLiteral* nliteral) 16 | { 17 | if(node_is(nliteral, NString)) 18 | return VMValueType::String; 19 | else if(node_is(nliteral, NBoolean)) 20 | return VMValueType::Bool; 21 | else if(node_is(nliteral, NReal)) 22 | return VMValueType::Double; 23 | else if(node_is(nliteral, NInteger)) 24 | return VMFunctions::integer_literal_type(static_cast(nliteral)->value); 25 | 26 | return VMValueType::Null; 27 | } 28 | 29 | string format_string(const VMValuePtr& format, const ValueList& args) 30 | { 31 | string s; 32 | int argidx = 0; 33 | 34 | for(const char* p = format->s_value.data(); *p != '\0'; p++) 35 | { 36 | if(*p != '%') // Eat words 37 | { 38 | if(*p == '\\') 39 | { 40 | p++; 41 | 42 | if(*p == '"') 43 | s += '\"'; 44 | else if(*p == 't') 45 | s += '\t'; 46 | else if(*p == 'r') 47 | s += '\r'; 48 | else if(*p == 'n') 49 | s += '\n'; 50 | else 51 | s += *p; 52 | 53 | continue; 54 | } 55 | 56 | s += *p; 57 | continue; 58 | } 59 | 60 | p++; 61 | 62 | string sw; 63 | double w = 0; 64 | 65 | while((!w && (*p == '-')) || ((*p >= '0') && (*p <= '9')) || (*p == '.')) // Eat width, if any 66 | { 67 | sw += *p; 68 | p++; 69 | } 70 | 71 | if(!sw.empty()) 72 | w = atof(sw.c_str()); 73 | 74 | switch(*p) 75 | { 76 | case 'd': // Signed integer 77 | case 'i': // Signed integer 78 | s += std::to_string(get_arg(args, argidx)->si_value); 79 | argidx++; 80 | continue; 81 | 82 | case 'u': // Unsigned integer 83 | s += std::to_string(get_arg(args, argidx)->ui_value); 84 | argidx++; 85 | continue; 86 | 87 | case 'x': // Hex integer 88 | case 'X': // Hex integer 89 | { 90 | string c = number_to_string(get_arg(args, argidx)->ui_value, 16); 91 | 92 | if(*p == 'X') // Uppercase... 93 | std::transform(c.begin(), c.end(), c.begin(), ::toupper); 94 | 95 | s += c; 96 | argidx++; 97 | continue; 98 | } 99 | 100 | case 'o': // Octal integer 101 | s += number_to_string(get_arg(args, argidx)->ui_value, 8); 102 | argidx++; 103 | continue; 104 | 105 | case 'c': // Character 106 | s += static_cast(get_arg(args, argidx)->ui_value); 107 | argidx++; 108 | continue; 109 | 110 | case 's': // String 111 | s += get_arg(args, argidx)->to_string(); 112 | argidx++; 113 | continue; 114 | 115 | case 'f': // Float 116 | case 'e': // Float 117 | case 'g': // Float 118 | s += std::to_string(get_arg(args, argidx)->d_value); 119 | argidx++; 120 | continue; 121 | 122 | case 'l': 123 | { 124 | p++; 125 | 126 | if(*p == 'f') 127 | { 128 | s += std::to_string(get_arg(args, argidx)->d_value); 129 | argidx++; 130 | continue; 131 | } 132 | 133 | argidx++; 134 | break; 135 | } 136 | 137 | case 'L': 138 | { 139 | p++; 140 | 141 | switch(*p) 142 | { 143 | case 'd': 144 | s += std::to_string(get_arg(args, argidx)->si_value); 145 | argidx++; 146 | continue; 147 | 148 | case 'u': 149 | s += std::to_string(get_arg(args, argidx)->ui_value); 150 | argidx++; 151 | continue; 152 | 153 | case 'x': 154 | case 'X': 155 | { 156 | string c = number_to_string(get_arg(args, argidx)->ui_value, 16); 157 | 158 | if(*p == 'X') // Uppercase... 159 | std::transform(c.begin(), c.end(), c.begin(), ::toupper); 160 | 161 | s += c; 162 | argidx++; 163 | continue; 164 | } 165 | } 166 | 167 | } 168 | 169 | default: 170 | break; 171 | } 172 | 173 | s += *p; 174 | } 175 | 176 | return s; 177 | } 178 | 179 | VMValueType::VMType integer_literal_type(uint64_t value) 180 | { 181 | if(value <= 0xFFFFFFFF) 182 | return VMValueType::u32; 183 | 184 | return VMValueType::u64; 185 | } 186 | 187 | VMValueType::VMType integer_literal_type(int64_t value) 188 | { 189 | if(value <= 0xFFFFFFFF) 190 | return VMValueType::s32; 191 | 192 | return VMValueType::s64; 193 | } 194 | 195 | VMValueType::VMType scalar_type(uint64_t bits, bool issigned, bool isfp) 196 | { 197 | if(isfp) 198 | return (bits < 64) ? VMValueType::Float : VMValueType::Double; 199 | 200 | if(bits <= 8) 201 | return issigned ? VMValueType::s8 : VMValueType::u8; 202 | 203 | if(bits <= 16) 204 | return issigned ? VMValueType::s16 : VMValueType::u16; 205 | 206 | if(bits <= 32) 207 | return issigned ? VMValueType::s32 : VMValueType::u32; 208 | 209 | return issigned ? VMValueType::s64 : VMValueType::u64; 210 | } 211 | 212 | 213 | VMValueType::VMType value_type(Node* node) 214 | { 215 | VMValueType::VMType valuetype = VMValueType::Null; 216 | 217 | if(node_inherits(node, NScalarType)) 218 | { 219 | NScalarType* nscalartype = static_cast(node); 220 | valuetype = VMFunctions::scalar_type(nscalartype->bits, nscalartype->is_signed, nscalartype->is_fp); 221 | } 222 | else if(node_inherits(node, NLiteral)) 223 | valuetype = VMFunctions::literal_type(static_cast(node)); 224 | 225 | if(valuetype == VMValueType::Null) 226 | throw std::runtime_error("Cannot get value-type of '" + node_typename(node) + "'"); 227 | 228 | return valuetype; 229 | } 230 | 231 | bool is_type_compatible(const VMValuePtr &vmvalue1, const VMValuePtr &vmvalue2) 232 | { 233 | if(vmvalue1->is_scalar() && vmvalue2->is_scalar()) 234 | return true; 235 | 236 | if(vmvalue1->is_compound() && vmvalue2->is_compound()) 237 | return node_typename(vmvalue1->value_typedef) == node_typename(vmvalue2->value_typedef); 238 | 239 | return vmvalue1->value_type == vmvalue2->value_type; 240 | } 241 | 242 | bool type_cast(const VMValuePtr &vmvalue, Node* node) 243 | { 244 | if(vmvalue->is_compound()) 245 | return node_typename(vmvalue->value_typedef) == node_typename(node); 246 | 247 | if(node_inherits(node, NScalarType) && vmvalue->is_scalar()) 248 | { 249 | NScalarType* nscalartype = static_cast(node); 250 | 251 | if(!nscalartype->is_fp && vmvalue->is_floating_point()) 252 | { 253 | if(nscalartype->is_signed) 254 | vmvalue->si_value = static_cast(vmvalue->d_value); 255 | else 256 | vmvalue->ui_value = static_cast(vmvalue->d_value); 257 | } 258 | else if(nscalartype->is_fp && vmvalue->is_integer()) 259 | { 260 | if(vmvalue->is_signed()) 261 | vmvalue->d_value = static_cast(vmvalue->si_value); 262 | else 263 | vmvalue->d_value = static_cast(vmvalue->ui_value); 264 | } 265 | 266 | vmvalue->value_type = VMFunctions::value_type(node); // NOTE: Handle sign 267 | return true; 268 | } 269 | 270 | return false; 271 | } 272 | 273 | string node_typeid(Node *node) 274 | { 275 | if(node_is(node, NIdentifier)) 276 | return static_cast(node)->value; 277 | else if(node_inherits(node, NType)) 278 | return node_typeid(static_cast(node)->name); 279 | 280 | throw std::runtime_error("Unhandled type '" + node_typename(node) + "'"); 281 | } 282 | 283 | } 284 | -------------------------------------------------------------------------------- /btvm/vm/vm_functions.h: -------------------------------------------------------------------------------- 1 | #ifndef BTVM_FUNCTIONS_H 2 | #define BTVM_FUNCTIONS_H 3 | 4 | #include 5 | #include 6 | #include "vmvalue.h" 7 | #include "ast.h" 8 | 9 | #define VMUnused(x) (void)x 10 | #define PLATFORM_BITS 8 11 | 12 | enum VMState { NoState = 0, 13 | Error, 14 | Break, Continue, Return }; 15 | 16 | namespace VMFunctions { 17 | 18 | using namespace std; 19 | 20 | typedef vector ValueList; 21 | 22 | template string number_to_string(T num, int base) 23 | { 24 | static const char* digits = "0123456789abcdef"; 25 | string value; 26 | 27 | do 28 | { 29 | value.insert(0, &digits[num % base], 1); 30 | num /= base; 31 | } 32 | while(num != 0); 33 | 34 | if(base == 16) 35 | { 36 | std::transform(value.begin(), value.end(), value.begin(), ::toupper); 37 | value += "h"; 38 | } 39 | else if(base == 8) 40 | value += "o"; 41 | else if(base == 2) 42 | value += "b"; 43 | 44 | return value; 45 | } 46 | 47 | inline int state_check(int* state) 48 | { 49 | if(*state == VMState::NoState) 50 | return *state; 51 | 52 | int s = *state; 53 | 54 | if((*state != VMState::Return) && (*state != VMState::Error)) 55 | *state = VMState::NoState; 56 | 57 | return s; 58 | } 59 | 60 | inline int64_t string_to_number(const string& s, int base) { return strtoul(s.c_str(), NULL, base); } 61 | inline double string_to_number(const string& s) { return atof(s.c_str()); } 62 | string format_string(const VMValuePtr &format, const ValueList& args); 63 | string node_typeid(Node* node); 64 | VMValueType::VMType integer_literal_type(int64_t value); 65 | VMValueType::VMType scalar_type(uint64_t bits, bool issigned, bool isfp); 66 | VMValueType::VMType value_type(Node *node); 67 | bool is_type_compatible(const VMValuePtr& vmvalue1, const VMValuePtr& vmvalue2); 68 | bool type_cast(const VMValuePtr& vmvalue, Node *node); 69 | void change_sign(const VMValuePtr& vmvalue); 70 | 71 | } 72 | 73 | #endif // BTVM_FUNCTIONS_H 74 | -------------------------------------------------------------------------------- /btvm/vm/vmvalue.cpp: -------------------------------------------------------------------------------- 1 | #include "vmvalue.h" 2 | #include "vm_functions.h" 3 | #include 4 | 5 | #define return_math_op(op) \ 6 | if(is_floating_point()) \ 7 | return *value_ref() op *rhs.value_ref(); \ 8 | if(rhs.is_floating_point()) \ 9 | return *value_ref() op *rhs.value_ref(); \ 10 | return *value_ref() op *rhs.value_ref(); 11 | 12 | #define return_cmp_op(op) \ 13 | if(is_signed() || rhs.is_signed()) \ 14 | return *value_ref() op *rhs.value_ref(); \ 15 | return *value_ref() op *rhs.value_ref(); 16 | 17 | VMValue::VMValue() : value_flags(VMValueFlags::None), value_type(VMValueType::Null), value_typedef(NULL), value_bgcolor(ColorInvalid), value_fgcolor(ColorInvalid), value_bits(-1), value_offset(0), s_value_ref(NULL), ui_value(0) { } 18 | VMValue::VMValue(bool value) : value_flags(VMValueFlags::None), value_type(VMValueType::Bool), value_typedef(NULL), value_bgcolor(ColorInvalid), value_fgcolor(ColorInvalid), value_bits(-1), value_offset(0), s_value_ref(NULL), ui_value(value) { } 19 | VMValue::VMValue(int64_t value) : value_flags(VMValueFlags::None), value_type(VMValueType::s64), value_typedef(NULL), value_bgcolor(ColorInvalid), value_fgcolor(ColorInvalid), value_bits(-1), value_offset(0), s_value_ref(NULL), ui_value(value) { } 20 | VMValue::VMValue(uint64_t value) : value_flags(VMValueFlags::None), value_type(VMValueType::u64), value_typedef(NULL), value_bgcolor(ColorInvalid), value_fgcolor(ColorInvalid), value_bits(-1), value_offset(0), s_value_ref(NULL), ui_value(value) { } 21 | VMValue::VMValue(double value) : value_flags(VMValueFlags::None), value_type(VMValueType::Double), value_typedef(NULL), value_bgcolor(ColorInvalid), value_fgcolor(ColorInvalid), value_bits(-1), value_offset(0), s_value_ref(NULL), d_value(value) { } 22 | 23 | VMValuePtr VMValue::allocate(const std::string &id) 24 | { 25 | VMValuePtr vmvalue = std::make_shared(); 26 | vmvalue->value_id = id; 27 | return vmvalue; 28 | } 29 | 30 | VMValuePtr VMValue::allocate(VMValueType::VMType valuetype, Node *type) 31 | { 32 | VMValuePtr vmvalue = std::make_shared(); 33 | vmvalue->value_type = valuetype; 34 | vmvalue->value_typedef = type; 35 | return vmvalue; 36 | } 37 | 38 | VMValuePtr VMValue::allocate(uint64_t bits, bool issigned, bool isfp, Node *type) { return VMValue::allocate(VMFunctions::scalar_type(bits, issigned, isfp), type); } 39 | 40 | VMValuePtr VMValue::allocate_literal(bool value, Node *type) 41 | { 42 | VMValuePtr vmvalue = VMValue::allocate(VMValueType::Bool, type); 43 | vmvalue->ui_value = value; 44 | return vmvalue; 45 | } 46 | 47 | VMValuePtr VMValue::allocate_literal(int64_t value, Node *type) 48 | { 49 | VMValuePtr vmvalue = VMValue::allocate(VMFunctions::integer_literal_type(value), type); 50 | vmvalue->si_value = value; 51 | return vmvalue; 52 | } 53 | 54 | VMValuePtr VMValue::allocate_literal(uint64_t value, Node *type) 55 | { 56 | VMValuePtr vmvalue = VMValue::allocate(VMFunctions::integer_literal_type(value), type); 57 | vmvalue->ui_value = value; 58 | return vmvalue; 59 | } 60 | 61 | VMValuePtr VMValue::allocate_literal(double value, Node *type) 62 | { 63 | VMValuePtr vmvalue = VMValue::allocate(VMValueType::Double, type); 64 | vmvalue->d_value = value; 65 | return vmvalue; 66 | } 67 | 68 | VMValuePtr VMValue::allocate_literal(const std::string &value, Node *type) 69 | { 70 | VMValuePtr vmvalue = VMValue::allocate(VMValueType::String, type); 71 | vmvalue->allocate_string(value, type); 72 | return vmvalue; 73 | } 74 | 75 | 76 | void VMValue::allocate_type(VMValueType::VMType valuetype, uint64_t size, Node *type) 77 | { 78 | value_type = valuetype; 79 | value_typedef = type; 80 | 81 | if(size > 0) 82 | s_value.resize(size, 0); 83 | } 84 | 85 | void VMValue::allocate_type(VMValueType::VMType valuetype, Node *type) { allocate_type(valuetype, 0, type); } 86 | void VMValue::allocate_scalar(uint64_t bits, bool issigned, bool isfp, Node *type) { allocate_type(VMFunctions::scalar_type(bits, issigned, isfp), type); } 87 | void VMValue::allocate_boolean(Node *type) { allocate_type(VMValueType::Bool, 1, type); } 88 | 89 | void VMValue::allocate_array(uint64_t size, Node *type) 90 | { 91 | allocate_type(VMValueType::Array, type); 92 | m_value.reserve(size); 93 | } 94 | 95 | void VMValue::allocate_string(uint64_t size, Node *type) { allocate_type(VMValueType::String, size + 1, type); } 96 | 97 | void VMValue::allocate_string(const std::string &s, Node *type) 98 | { 99 | allocate_string(s.size(), type); 100 | std::copy(s.begin(), s.end(), s_value.begin()); 101 | } 102 | 103 | VMValuePtr VMValue::copy_value(const VMValue &vmsrc) { return std::make_shared(vmsrc); } 104 | 105 | void VMValue::change_sign() 106 | { 107 | if(value_type == VMValueType::u8) 108 | value_type = VMValueType::s8; 109 | else if(value_type == VMValueType::u16) 110 | value_type = VMValueType::s16; 111 | else if(value_type == VMValueType::u32) 112 | value_type = VMValueType::s32; 113 | else if(value_type == VMValueType::u64) 114 | value_type = VMValueType::s64; 115 | else if(value_type == VMValueType::s8) 116 | value_type = VMValueType::u8; 117 | else if(value_type == VMValueType::s16) 118 | value_type = VMValueType::u16; 119 | else if(value_type == VMValueType::s32) 120 | value_type = VMValueType::u32; 121 | else if(value_type == VMValueType::s64) 122 | value_type = VMValueType::u64; 123 | } 124 | 125 | void VMValue::assign(const VMValue &rhs) 126 | { 127 | if(is_floating_point()) 128 | *value_ref() = rhs.d_value; 129 | else if(is_integer()) 130 | { 131 | if(is_signed()) 132 | *value_ref() = rhs.si_value; 133 | else 134 | *value_ref() = rhs.ui_value; 135 | } 136 | else 137 | { 138 | if(is_reference()) 139 | std::memcpy(s_value_ref, rhs.s_value.data(), rhs.s_value.size()); 140 | else 141 | s_value = rhs.s_value; 142 | } 143 | } 144 | 145 | VMValuePtr VMValue::create_reference(uint64_t offset, VMValueType::VMType valuetype) const 146 | { 147 | VMValuePtr vmvalue = std::make_shared(); 148 | vmvalue->value_flags = value_flags | VMValueFlags::Reference; 149 | vmvalue->value_type = (valuetype != VMValueType::Null) ? valuetype : value_type; 150 | vmvalue->value_typedef = value_typedef; 151 | vmvalue->s_value_ref = const_cast(value_ref()) + offset; 152 | return vmvalue; 153 | } 154 | 155 | VMValuePtr VMValue::is_member(const std::string &member) const 156 | { 157 | for(auto it = m_value.begin(); it != m_value.end(); it++) 158 | { 159 | if((*it)->value_id == member) 160 | return *it; 161 | } 162 | 163 | return NULL; 164 | } 165 | 166 | bool VMValue::is_template() const { return (!is_const() && !is_local()); } 167 | bool VMValue::is_const() const { return (value_flags & VMValueFlags::Const); } 168 | bool VMValue::is_local() const { return (value_flags & VMValueFlags::Local); } 169 | bool VMValue::is_reference() const { return (value_flags & VMValueFlags::Reference); } 170 | 171 | bool VMValue::is_readable() const { return (value_type >= VMValueType::String) || (value_type == VMValueType::Enum); } 172 | bool VMValue::is_null() const { return (value_type == VMValueType::Null); } 173 | bool VMValue::is_string() const { return (value_type == VMValueType::String); } 174 | bool VMValue::is_boolean() const { return (value_type == VMValueType::Bool); } 175 | bool VMValue::is_array() const { return (value_type == VMValueType::Array); } 176 | bool VMValue::is_enum() const { return (value_type == VMValueType::Enum); } 177 | bool VMValue::is_union() const { return (value_type == VMValueType::Union); } 178 | bool VMValue::is_struct() const { return (value_type == VMValueType::Struct); } 179 | bool VMValue::is_compound() const { return (value_type >= VMValueType::Enum) && (value_type <= VMValueType::Struct); } 180 | bool VMValue::is_integer() const { return (value_type >= VMValueType::Bool) && (value_type <= VMValueType::s64); } 181 | bool VMValue::is_floating_point() const { return (value_type >= VMValueType::Float) && (value_type <= VMValueType::Double); } 182 | bool VMValue::is_scalar() const { return is_integer() || is_floating_point(); } 183 | 184 | bool VMValue::is_negative() const 185 | { 186 | if(is_integer()) 187 | return *value_ref() < 0; 188 | 189 | if(is_floating_point()) 190 | return *value_ref() < 0; 191 | 192 | return false; 193 | } 194 | 195 | bool VMValue::is_signed() const 196 | { 197 | switch(value_type) 198 | { 199 | case VMValueType::s8: 200 | case VMValueType::s16: 201 | case VMValueType::s32: 202 | case VMValueType::s64: 203 | return true; 204 | 205 | default: 206 | break; 207 | } 208 | 209 | return false; 210 | } 211 | 212 | std::string VMValue::type_name() const 213 | { 214 | if(value_type == VMValueType::Null) 215 | return "null"; 216 | else if(value_type == VMValueType::Enum) 217 | return "enum"; 218 | else if(value_type == VMValueType::Union) 219 | return "union"; 220 | else if(value_type == VMValueType::Struct) 221 | return "struct"; 222 | else if(value_type == VMValueType::Array) 223 | return "array"; 224 | else if(value_type == VMValueType::String) 225 | return "string"; 226 | else if(value_type == VMValueType::Bool) 227 | return "bool"; 228 | else if(value_type == VMValueType::u8) 229 | return "u8"; 230 | else if(value_type == VMValueType::u16) 231 | return "u16"; 232 | else if(value_type == VMValueType::u32) 233 | return "u32"; 234 | else if(value_type == VMValueType::u64) 235 | return "u64"; 236 | else if(value_type == VMValueType::s8) 237 | return "s8"; 238 | else if(value_type == VMValueType::s16) 239 | return "s16"; 240 | else if(value_type == VMValueType::s32) 241 | return "s32"; 242 | else if(value_type == VMValueType::s64) 243 | return "s64"; 244 | else if(value_type == VMValueType::Float) 245 | return "float"; 246 | else if(value_type == VMValueType::Double) 247 | return "double"; 248 | 249 | return "unknown"; 250 | } 251 | 252 | std::string VMValue::to_string() const 253 | { 254 | std::string s = printable(10); 255 | 256 | if(s.empty()) 257 | throw std::runtime_error("Trying to converting a '" + type_name() + "' to string"); 258 | 259 | return s; 260 | } 261 | 262 | std::string VMValue::printable(int base) const 263 | { 264 | if(is_integer()) 265 | return VMFunctions::number_to_string((is_signed() ? *value_ref() : *value_ref()), base); 266 | else if(is_floating_point()) 267 | return std::to_string(*value_ref()); 268 | else if(is_string()) 269 | return value_ref(); 270 | 271 | return std::string(); 272 | } 273 | 274 | int32_t VMValue::length() const 275 | { 276 | if(!is_string()) 277 | return 0; 278 | 279 | return std::strlen(value_ref()); 280 | } 281 | 282 | VMValue::operator bool() const 283 | { 284 | if(is_scalar()) 285 | return (*value_ref() != 0); 286 | 287 | return false; 288 | } 289 | 290 | bool VMValue::operator ==(const VMValue& rhs) const 291 | { 292 | if(is_string()) 293 | return !std::strcmp(value_ref(), rhs.value_ref()); 294 | 295 | return_cmp_op(==); 296 | } 297 | 298 | bool VMValue::operator !=(const VMValue& rhs) const 299 | { 300 | if(is_string()) 301 | return std::strcmp(value_ref(), rhs.value_ref()); 302 | 303 | return_cmp_op(!=); 304 | } 305 | 306 | bool VMValue::operator <=(const VMValue& rhs) const { return_cmp_op(<=); } 307 | bool VMValue::operator >=(const VMValue& rhs) const { return_cmp_op(>=); } 308 | bool VMValue::operator <(const VMValue& rhs) const { return_cmp_op(<); } 309 | bool VMValue::operator >(const VMValue& rhs) const { return_cmp_op(>); } 310 | 311 | VMValue& VMValue::operator ++() 312 | { 313 | if(is_floating_point()) 314 | (*value_ref())++; 315 | else 316 | (*value_ref())++; 317 | 318 | return *this; 319 | } 320 | 321 | VMValue VMValue::operator ++(int) 322 | { 323 | VMValue vmvalue = *this; 324 | ++*this; 325 | return vmvalue; 326 | } 327 | 328 | VMValue& VMValue::operator --() 329 | { 330 | if(is_floating_point()) 331 | (*value_ref())--; 332 | else 333 | (*value_ref())--; 334 | 335 | return *this; 336 | } 337 | 338 | VMValue VMValue::operator --(int) 339 | { 340 | VMValue vmvalue = *this; 341 | --*this; 342 | return vmvalue; 343 | } 344 | 345 | VMValue VMValue::operator !() const { return !(*value_ref()); } 346 | 347 | VMValue VMValue::operator ~() const 348 | { 349 | if((value_type == VMValueType::s8) || (value_type == VMValueType::u8)) 350 | return static_cast(~(*value_ref())); 351 | 352 | if((value_type == VMValueType::s16) || (value_type == VMValueType::u16)) 353 | return static_cast(~(*value_ref())); 354 | 355 | if((value_type == VMValueType::s32) || (value_type == VMValueType::u32)) 356 | return static_cast(~(*value_ref())); 357 | 358 | return ~(*value_ref()); 359 | } 360 | 361 | VMValue VMValue::operator -() const 362 | { 363 | if(!is_integer()) 364 | throw std::runtime_error("Trying to change sign in a '" + type_name()); 365 | 366 | VMValue vmvalue = *this; 367 | vmvalue.si_value = -vmvalue.si_value; 368 | vmvalue.change_sign(); 369 | return vmvalue; 370 | } 371 | 372 | VMValue VMValue::operator +(const VMValue& rhs) const 373 | { 374 | if(is_string()) 375 | { 376 | VMValue vmvalue; 377 | vmvalue.s_value.resize(s_value.size() + rhs.s_value.size()); 378 | vmvalue.s_value.insert(vmvalue.s_value.end(), s_value.begin(), s_value.end()); 379 | vmvalue.s_value.insert(vmvalue.s_value.end(), rhs.s_value.begin(), rhs.s_value.end()); 380 | return vmvalue; 381 | } 382 | 383 | return_math_op(+); 384 | } 385 | 386 | VMValue VMValue::operator -(const VMValue& rhs) const { return_math_op(-) } 387 | VMValue VMValue::operator *(const VMValue& rhs) const { return_math_op(*); } 388 | VMValue VMValue::operator /(const VMValue& rhs) const { return_math_op(/); } 389 | 390 | VMValue VMValue::operator %(const VMValue& rhs) const { return *value_ref() % *rhs.value_ref(); } 391 | VMValue VMValue::operator &(const VMValue& rhs) const { return *value_ref() & *rhs.value_ref(); } 392 | VMValue VMValue::operator |(const VMValue& rhs) const { return *value_ref() | *rhs.value_ref(); } 393 | VMValue VMValue::operator ^(const VMValue& rhs) const { return *value_ref() ^ *rhs.value_ref(); } 394 | VMValue VMValue::operator <<(const VMValue& rhs) const { return *value_ref() << *rhs.value_ref(); } 395 | VMValue VMValue::operator >>(const VMValue& rhs) const { return *value_ref() >> *rhs.value_ref(); } 396 | 397 | VMValuePtr VMValue::operator[](const VMValue &index) const 398 | { 399 | if(is_string()) 400 | return VMValue::create_reference(index.ui_value, VMValueType::s8); 401 | 402 | return m_value[index.ui_value]; 403 | } 404 | 405 | VMValuePtr VMValue::operator[](const std::string &member) const 406 | { 407 | for(auto it = m_value.cbegin(); it != m_value.cend(); it++) 408 | { 409 | if((*it)->value_id == member) 410 | return *it; 411 | } 412 | 413 | return VMValuePtr(); 414 | } 415 | -------------------------------------------------------------------------------- /btvm/vm/vmvalue.h: -------------------------------------------------------------------------------- 1 | #ifndef VMVALUE_H 2 | #define VMVALUE_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #define ColorInvalid 0xFFFFFFFF 11 | 12 | class Node; 13 | class VMValue; 14 | 15 | namespace VMValueType 16 | { 17 | enum VMType { Null = 0, 18 | Enum, Union, Struct, 19 | Array, String, 20 | Bool, 21 | u8, u16, u32, u64, 22 | s8, s16, s32, s64, 23 | Float, Double }; 24 | } 25 | 26 | namespace VMValueFlags 27 | { 28 | enum VMFlags { None = 0, Const = 1, Local = 2, Reference = 4 }; 29 | } 30 | 31 | typedef std::vector VMString; 32 | typedef std::shared_ptr VMValuePtr; 33 | typedef std::vector VMValueMembers; 34 | 35 | struct VMValue 36 | { 37 | VMValue(); 38 | VMValue(bool value); 39 | VMValue(int64_t value); 40 | VMValue(uint64_t value); 41 | VMValue(double value); 42 | 43 | static VMValuePtr allocate(const std::string& id = std::string()); 44 | static VMValuePtr allocate(VMValueType::VMType valuetype, Node* type = NULL); 45 | static VMValuePtr allocate(uint64_t bits, bool issigned, bool isfp, Node* type = NULL); 46 | static VMValuePtr allocate_literal(bool value, Node* type = NULL); 47 | static VMValuePtr allocate_literal(int64_t value, Node* type = NULL); 48 | static VMValuePtr allocate_literal(uint64_t value, Node* type = NULL); 49 | static VMValuePtr allocate_literal(double value, Node* type = NULL); 50 | static VMValuePtr allocate_literal(const std::string& value, Node* type = NULL); 51 | void allocate_type(VMValueType::VMType valuetype, Node* type); 52 | void allocate_type(VMValueType::VMType valuetype, uint64_t size, Node* type); 53 | void allocate_scalar(uint64_t bits, bool issigned, bool isfp, Node* type = NULL); 54 | void allocate_boolean(Node* type); 55 | void allocate_array(uint64_t size, Node* type); 56 | void allocate_string(uint64_t size, Node* type); 57 | void allocate_string(const std::string& s, Node* type); 58 | 59 | static VMValuePtr copy_value(const VMValue &vmsrc); 60 | 61 | void change_sign(); 62 | void assign(const VMValue& rhs); 63 | VMValuePtr create_reference(uint64_t offset, VMValueType::VMType valuetype = VMValueType::Null) const; 64 | VMValuePtr is_member(const std::string& member) const; 65 | 66 | bool is_template() const; 67 | bool is_const() const; 68 | bool is_local() const; 69 | bool is_reference() const; 70 | 71 | bool is_readable() const; 72 | bool is_null() const; 73 | bool is_string() const; 74 | bool is_boolean() const; 75 | bool is_array() const; 76 | bool is_enum() const; 77 | bool is_union() const; 78 | bool is_struct() const; 79 | bool is_compound() const; 80 | bool is_integer() const; 81 | bool is_floating_point() const; 82 | bool is_scalar() const; 83 | bool is_negative() const; 84 | bool is_signed() const; 85 | 86 | std::string type_name() const; 87 | std::string to_string() const; 88 | std::string printable(int base = 10) const; 89 | int32_t length() const; 90 | 91 | operator bool() const; 92 | 93 | bool operator ==(const VMValue& rhs) const; 94 | bool operator !=(const VMValue& rhs) const; 95 | bool operator <=(const VMValue& rhs) const; 96 | bool operator >=(const VMValue& rhs) const; 97 | bool operator <(const VMValue& rhs) const; 98 | bool operator >(const VMValue& rhs) const; 99 | 100 | VMValue& operator ++(); 101 | VMValue& operator --(); 102 | VMValue operator ++(int); 103 | VMValue operator --(int); 104 | VMValue operator !() const; 105 | VMValue operator ~() const; 106 | VMValue operator -() const; 107 | VMValue operator +(const VMValue& rhs) const; 108 | VMValue operator -(const VMValue& rhs) const; 109 | VMValue operator *(const VMValue& rhs) const; 110 | VMValue operator /(const VMValue& rhs) const; 111 | VMValue operator %(const VMValue& rhs) const; 112 | VMValue operator &(const VMValue& rhs) const; 113 | VMValue operator |(const VMValue& rhs) const; 114 | VMValue operator ^(const VMValue& rhs) const; 115 | VMValue operator <<(const VMValue& rhs) const; 116 | VMValue operator >>(const VMValue& rhs) const; 117 | VMValuePtr operator[](const VMValue& index) const; 118 | VMValuePtr operator[](const std::string& member) const; 119 | 120 | template const T* value_ref() const; 121 | template T* value_ref(); 122 | 123 | size_t value_flags; 124 | VMValueType::VMType value_type; 125 | Node* value_typedef; 126 | std::string value_id; 127 | std::string value_typeid; 128 | std::string value_comment; 129 | uint32_t value_bgcolor; 130 | uint32_t value_fgcolor; 131 | int64_t value_bits; 132 | uint64_t value_offset; 133 | 134 | VMValueMembers m_value; 135 | VMString s_value; 136 | 137 | union // By reference 138 | { 139 | int64_t* si_value_ref; 140 | uint64_t* ui_value_ref; 141 | double* d_value_ref; 142 | char* s_value_ref; 143 | }; 144 | 145 | union // By value 146 | { 147 | int64_t si_value; 148 | uint64_t ui_value; 149 | double d_value; 150 | }; 151 | }; 152 | 153 | template const T* VMValue::value_ref() const 154 | { 155 | if(is_integer() || is_enum()) 156 | { 157 | if(is_signed()) 158 | return reinterpret_cast((is_reference() ? si_value_ref : &si_value)); 159 | 160 | return reinterpret_cast((is_reference() ? ui_value_ref : &ui_value)); 161 | } 162 | else if(is_floating_point()) 163 | return reinterpret_cast((is_reference() ? d_value_ref : &d_value)); 164 | 165 | return reinterpret_cast((is_reference() ? s_value_ref : s_value.data())); 166 | } 167 | 168 | template T* VMValue::value_ref() { return const_cast(static_cast(this)->value_ref()); } 169 | 170 | struct VMValueHasher 171 | { 172 | std::size_t operator()(const VMValue& key) const 173 | { 174 | if(key.is_integer()) 175 | return std::hash()(*key.value_ref()); 176 | else if(key.is_floating_point()) 177 | return std::hash()(*key.value_ref()); 178 | else if(key.is_string()) 179 | return std::hash()(key.value_ref()); 180 | 181 | throw std::runtime_error("Cannot hash '" + key.type_name() + "'"); 182 | return std::size_t(); 183 | } 184 | }; 185 | 186 | #endif // VMVALUE_H 187 | -------------------------------------------------------------------------------- /generator/Makefile: -------------------------------------------------------------------------------- 1 | bt_lexer: bt_parser; 2 | re2c -o bt_lexer.cpp bt_lexer.re 3 | mv bt_lexer.cpp .. 4 | cp bt_lexer.h .. 5 | 6 | bt_parser: 7 | lemon bt_parser.y -s | true 8 | mv bt_parser.c ../bt_parser.cpp 9 | mv bt_parser.h .. 10 | -------------------------------------------------------------------------------- /generator/bt_lexer.h: -------------------------------------------------------------------------------- 1 | #ifndef BT_LEXER_H 2 | #define BT_LEXER_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | using namespace std; 10 | 11 | class BTLexer 12 | { 13 | public: 14 | struct Token { int type; unsigned int line; std::string value; }; 15 | 16 | public: 17 | BTLexer(const char* s); 18 | list lex(); 19 | 20 | private: 21 | string getString(const char* start, const char* end) const; 22 | 23 | private: 24 | const char* _cursor; 25 | const char* _start; 26 | const char* _marker; 27 | }; 28 | 29 | #endif // FLINI_LEXER_H 30 | -------------------------------------------------------------------------------- /generator/bt_lexer.re: -------------------------------------------------------------------------------- 1 | #include "bt_lexer.h" 2 | #include "bt_parser.h" 3 | 4 | #define TOKEN_STRING string(start, this->_cursor - start) 5 | #define TOKEN_STRING_LITERAL string(start + 1, this->_cursor - (start + 2)) 6 | 7 | #define UNKNOWN_TOKEN cout << "Unknown token '" << TOKEN_STRING << "' near line " << currentline << endl; \ 8 | continue; 9 | 10 | #define TOKENIZE(token_type) token.value = TOKEN_STRING; \ 11 | token.type = token_type; \ 12 | token.line = currentline; \ 13 | tokens.push_back(token); \ 14 | continue; 15 | 16 | #define TOKENIZE_STRING_LITERAL(token_type) token.value = TOKEN_STRING_LITERAL; \ 17 | token.type = token_type; \ 18 | token.line = currentline; \ 19 | tokens.push_back(token); \ 20 | continue; 21 | 22 | BTLexer::BTLexer(const char* s): _cursor(s), _start(NULL), _marker(NULL) 23 | { 24 | } 25 | 26 | string BTLexer::getString(const char* start, const char* end) const 27 | { 28 | return string(start, end - start); 29 | } 30 | 31 | list BTLexer::lex() 32 | { 33 | list tokens; 34 | unsigned int currentline = 0; 35 | 36 | for(; ;) 37 | { 38 | Token token; 39 | const char* start = this->_cursor; 40 | 41 | /*!re2c 42 | re2c:define:YYCTYPE = char; 43 | re2c:define:YYCURSOR = this->_cursor; 44 | re2c:define:YYMARKER = this->_marker; 45 | re2c:yyfill:enable = 0; 46 | 47 | LINE_FEED = [\n]; 48 | WHITESPACE = [\r\t\\ ]+; 49 | LITERAL_REAL = [0-9]*"."[0-9]* | [0-9]+"."; 50 | LITERAL_OCT = "0"[0-7]*; 51 | LITERAL_DEC = [1-9][0-9]*; 52 | LITERAL_HEX = "0x"[0-9a-fA-F]+; 53 | LITERAL_CHAR = [L]?"'"("."|[^\"])"'"; 54 | LITERAL_STRING = [L]?"\""("."|[^\"])*"\""; 55 | IDENTIFIER = [a-zA-Z_][a-zA-Z_0-9]*; 56 | LINE_COMMENT = "\x2f\x2f"[^\n]*"\n"; 57 | MULTI_COMMENT = "\x2f\x2a"([^*]|("*"[^/]))*"\x2a\x2f"; 58 | 59 | "\x00" { break; } 60 | LINE_FEED | LINE_COMMENT { currentline++; continue; } 61 | WHITESPACE | MULTI_COMMENT { continue; } 62 | 63 | "(" { TOKENIZE(BTT_O_ROUND) } 64 | ")" { TOKENIZE(BTT_C_ROUND) } 65 | "[" { TOKENIZE(BTT_O_SQUARE) } 66 | "]" { TOKENIZE(BTT_C_SQUARE) } 67 | "{" { TOKENIZE(BTT_O_CURLY) } 68 | "}" { TOKENIZE(BTT_C_CURLY) } 69 | "," { TOKENIZE(BTT_COMMA) } 70 | "." { TOKENIZE(BTT_DOT) } 71 | ";" { TOKENIZE(BTT_SEMICOLON) } 72 | ":" { TOKENIZE(BTT_COLON) } 73 | "=" { TOKENIZE(BTT_ASSIGN) } 74 | "?" { TOKENIZE(BTT_QUESTION) } 75 | 76 | "&" { TOKENIZE(BTT_BIN_AND) } 77 | "|" { TOKENIZE(BTT_BIN_OR) } 78 | "^" { TOKENIZE(BTT_BIN_XOR) } 79 | "~" { TOKENIZE(BTT_BIN_NOT) } 80 | 81 | "&&" { TOKENIZE(BTT_LOG_AND) } 82 | "||" { TOKENIZE(BTT_LOG_OR) } 83 | "!" { TOKENIZE(BTT_LOG_NOT) } 84 | 85 | "==" { TOKENIZE(BTT_EQ) } 86 | "!=" { TOKENIZE(BTT_NE) } 87 | "<" { TOKENIZE(BTT_LT) } 88 | ">" { TOKENIZE(BTT_GT) } 89 | "<=" { TOKENIZE(BTT_LE) } 90 | ">=" { TOKENIZE(BTT_GE) } 91 | 92 | "+=" { TOKENIZE(BTT_ADD_ASSIGN) } 93 | "-=" { TOKENIZE(BTT_SUB_ASSIGN) } 94 | "*=" { TOKENIZE(BTT_MUL_ASSIGN) } 95 | "/=" { TOKENIZE(BTT_DIV_ASSIGN) } 96 | "&=" { TOKENIZE(BTT_AND_ASSIGN) } 97 | "|=" { TOKENIZE(BTT_OR_ASSIGN) } 98 | "^=" { TOKENIZE(BTT_XOR_ASSIGN) } 99 | "<<=" { TOKENIZE(BTT_LS_ASSIGN) } 100 | ">>=" { TOKENIZE(BTT_RS_ASSIGN) } 101 | 102 | "++" { TOKENIZE(BTT_INC) } 103 | "--" { TOKENIZE(BTT_DEC) } 104 | 105 | "+" { TOKENIZE(BTT_ADD) } 106 | "-" { TOKENIZE(BTT_SUB) } 107 | "*" { TOKENIZE(BTT_MUL) } 108 | "/" { TOKENIZE(BTT_DIV) } 109 | "%" { TOKENIZE(BTT_MOD) } 110 | "<<" { TOKENIZE(BTT_LSL) } 111 | ">>" { TOKENIZE(BTT_LSR) } 112 | 113 | "void" { TOKENIZE(BTT_VOID) } 114 | "bool" { TOKENIZE(BTT_BOOL) } 115 | "string" { TOKENIZE(BTT_STRING) } 116 | "wstring" { TOKENIZE(BTT_WSTRING) } 117 | "wchar_t" { TOKENIZE(BTT_WCHAR) } 118 | "char" | "CHAR" { TOKENIZE(BTT_CHAR) } 119 | "byte" | "BYTE" { TOKENIZE(BTT_BYTE) } 120 | "uchar" | "UCHAR" { TOKENIZE(BTT_UCHAR) } 121 | "ubyte" | "UBYTE" { TOKENIZE(BTT_UBYTE) } 122 | "short" | "int16" | "SHORT" | "INT16" { TOKENIZE(BTT_SHORT) } 123 | "ushort" | "uint16" | "USHORT" | "UINT16" | "WORD" { TOKENIZE(BTT_USHORT) } 124 | "int" | "int32" | "long" | "INT" | "INT32" | "LONG" { TOKENIZE(BTT_INT32) } 125 | "uint" | "uint32" | "ulong" | "UINT" | "UINT32" | "ULONG" | "DWORD" { TOKENIZE(BTT_UINT32) } 126 | "int64" | "quad" | "INT64" | "QUAD" | "__int64" { TOKENIZE(BTT_INT64) } 127 | "uint64" | "uquad" | "UINT64" | "UQUAD" | "QWORD" | "__uint64" { TOKENIZE(BTT_UINT64) } 128 | "hfloat" | "HFLOAT" { TOKENIZE(BTT_HFLOAT) } 129 | "float" | "FLOAT" { TOKENIZE(BTT_FLOAT) } 130 | "double" | "DOUBLE" { TOKENIZE(BTT_DOUBLE) } 131 | "time_t" { TOKENIZE(BTT_TIME) } 132 | "DOSDATE" { TOKENIZE(BTT_DOSDATE) } 133 | "DOSTIME" { TOKENIZE(BTT_DOSTIME) } 134 | "OLETIME" { TOKENIZE(BTT_OLETIME) } 135 | "FILETIME" { TOKENIZE(BTT_FILETIME) } 136 | 137 | "const" { TOKENIZE(BTT_CONST) } 138 | "local" { TOKENIZE(BTT_LOCAL) } 139 | "break" { TOKENIZE(BTT_BREAK) } 140 | "continue" { TOKENIZE(BTT_CONTINUE) } 141 | "sizeof" { TOKENIZE(BTT_SIZEOF) } 142 | "typedef" { TOKENIZE(BTT_TYPEDEF) } 143 | "enum" { TOKENIZE(BTT_ENUM) } 144 | "struct" { TOKENIZE(BTT_STRUCT) } 145 | "union" { TOKENIZE(BTT_UNION) } 146 | "return" { TOKENIZE(BTT_RETURN) } 147 | "case" { TOKENIZE(BTT_CASE) } 148 | "default" { TOKENIZE(BTT_DEFAULT) } 149 | "for" { TOKENIZE(BTT_FOR) } 150 | "if" { TOKENIZE(BTT_IF) } 151 | "else" { TOKENIZE(BTT_ELSE) } 152 | "switch" { TOKENIZE(BTT_SWITCH) } 153 | "while" { TOKENIZE(BTT_WHILE) } 154 | "do" { TOKENIZE(BTT_DO) } 155 | "const" { TOKENIZE(BTT_CONST) } 156 | "signed" { TOKENIZE(BTT_SIGNED) } 157 | "unsigned" { TOKENIZE(BTT_UNSIGNED) } 158 | "true" { TOKENIZE(BTT_TRUE) } 159 | "false" { TOKENIZE(BTT_FALSE) } 160 | 161 | IDENTIFIER { TOKENIZE(BTT_IDENTIFIER) } 162 | LITERAL_REAL { TOKENIZE(BTT_LITERAL_REAL) } 163 | LITERAL_OCT { TOKENIZE(BTT_LITERAL_OCT) } 164 | LITERAL_DEC { TOKENIZE(BTT_LITERAL_DEC) } 165 | LITERAL_HEX { TOKENIZE(BTT_LITERAL_HEX) } 166 | LITERAL_CHAR { TOKENIZE_STRING_LITERAL(BTT_LITERAL_CHAR) } 167 | LITERAL_STRING { TOKENIZE_STRING_LITERAL(BTT_LITERAL_STRING) } 168 | 169 | * { UNKNOWN_TOKEN } 170 | */ 171 | } 172 | 173 | return tokens; 174 | } 175 | 176 | -------------------------------------------------------------------------------- /generator/bt_parser.y: -------------------------------------------------------------------------------- 1 | %name BTParser 2 | 3 | %include { 4 | #include 5 | #include "btvm/vm/vm_functions.h" 6 | #include "btvm/btvm.h" 7 | #include "bt_lexer.h" 8 | } 9 | 10 | %extra_argument { BTVM* btvm } 11 | %default_type { Node* } 12 | %token_type { BTLexer::Token* } 13 | %token_prefix BTT_ 14 | 15 | %syntax_error { 16 | VMUnused(yymajor); // Silence compiler warnings 17 | btvm->syntaxError(TOKEN->value, TOKEN->line); 18 | } 19 | 20 | %stack_overflow { 21 | btvm->error("Stack overflow"); 22 | } 23 | 24 | %type stm_list { NodeList* } 25 | %type var_list { NodeList* } 26 | %type var_list_no_assign { NodeList* } 27 | %type case_stms { NodeList* } 28 | %type enum_def { NodeList* } 29 | %type struct_stms { NodeList* } 30 | %type params { NodeList* } 31 | %type decls { NodeList* } 32 | %type expr { NodeList* } 33 | %type args_decl { NodeList* } 34 | %type custom_vars { NodeList* } 35 | %type custom_var_decl { NodeList* } 36 | %type scalar { NScalarType* } 37 | %type string { NType* } 38 | %type character { NType* } 39 | %type datetime { NType* } 40 | %type param { NArgument* } 41 | %type var { NVariable* } 42 | %type var_no_assign { NVariable* } 43 | %type custom_var { NCustomVariable* } 44 | %type block { NBlock* } 45 | %type enum_type { NType* } 46 | %type type { NType* } 47 | %type id { NIdentifier* } 48 | %type sign { int } 49 | 50 | program ::= decls(B). { btvm->loadAST(new NBlock(*B)); delete B; } 51 | 52 | decls(A) ::= decls decl(B). { A->push_back(B); } 53 | decls(A) ::= decl(B). { A = new NodeList(); A->push_back(B); } 54 | 55 | decl(A) ::= func_decl(B). { A = B; } 56 | decl(A) ::= struct_decl(B). { A = B; } 57 | decl(A) ::= union_decl(B). { A = B; } 58 | decl(A) ::= enum_decl(B). { A = B; } 59 | decl(A) ::= var_decl(B). { A = B; } 60 | decl(A) ::= typedef_decl(B). { A = B; } 61 | decl(A) ::= stm(B). { A = B; } 62 | 63 | // ======================================================= 64 | // Function Declaration 65 | // ======================================================= 66 | 67 | func_decl(A) ::= type(B) id(C) O_ROUND params(D) C_ROUND block(E). { A = new NFunction(B, C, *D, E); delete D; } 68 | func_decl(A) ::= type(B) id(C) O_ROUND C_ROUND block(D). { A = new NFunction(B, C, D); } 69 | 70 | params(A) ::= params COMMA param(B). { A->push_back(B); } 71 | params(A) ::= param(B). { A = new NodeList(); A->push_back(B); } 72 | params(A) ::= VOID. { A = new NodeList(); } 73 | 74 | param(A) ::= type(B) BIN_AND id(C) array(D). { A = new NArgument(B, C, D); A->by_reference = true; } 75 | param(A) ::= type(B) id(C) array(D). { A = new NArgument(B, C, D); } 76 | param(A) ::= id(B) BIN_AND id(C) array(D). { A = new NArgument(B, C, D); A->by_reference = true; } 77 | param(A) ::= id(B) id(C) array(D). { A = new NArgument(B, C, D); } 78 | 79 | // ======================================================= 80 | // Type Declaration 81 | // ======================================================= 82 | 83 | typedef_decl(A) ::= TYPEDEF type(B) id(C) array(D) custom_var_decl(E) SEMICOLON. { A = new NTypedef(B, C, *E); B->size = D; delete E; } 84 | 85 | struct_decl(A) ::= STRUCT id(B) args_decl(C) O_CURLY struct_stms(D) C_CURLY custom_var_decl(E) SEMICOLON. { A = new NStruct(B, *C, *D, *E); delete C; delete D; delete E; } 86 | 87 | union_decl(A) ::= UNION id(B) args_decl(C) O_CURLY struct_stms(D) C_CURLY custom_var_decl(E) SEMICOLON. { A = new NUnion(B, *C, *D, *E); delete C; delete D; delete E; } 88 | 89 | enum_decl(A) ::= ENUM enum_type(B) id(C) O_CURLY enum_def(D) C_CURLY SEMICOLON. { A = new NEnum(C, *D, B); delete D; } 90 | enum_decl(A) ::= ENUM enum_type(B) O_CURLY enum_def(C) C_CURLY SEMICOLON. { A = new NEnum(*C, B); delete C; } 91 | enum_decl(A) ::= ENUM type(B) O_CURLY enum_def(C) C_CURLY SEMICOLON. { A = new NEnum(*C, B); delete C; } 92 | 93 | custom_var_decl(A) ::= LT custom_vars(B) GT. { A = B; } 94 | custom_var_decl(A) ::= . { A = new NodeList(); } 95 | 96 | args_decl(A) ::= O_ROUND params(B) C_ROUND. { A = B; } 97 | args_decl(A) ::= . { A = new NodeList(); } 98 | 99 | // ======================================================= 100 | // Variable Declaration 101 | // ======================================================= 102 | 103 | var_decl(A) ::= CONST type(B) var(C) var_list(D) SEMICOLON. { C->type = B; C->is_const = true; C->names = *D; A = C; delete D; } 104 | var_decl(A) ::= CONST id(B) var(C) var_list(D) SEMICOLON. { C->type = new NType(B); C->is_const = true; C->names = *D; A = C; delete D; } 105 | var_decl(A) ::= LOCAL type(B) var(C) var_list(D) SEMICOLON. { C->type = B; C->is_local = true; C->names = *D; A = C; delete D; } 106 | var_decl(A) ::= LOCAL id(B) var(C) var_list(D) SEMICOLON. { C->type = new NType(B); C->is_local = true; C->names = *D; A = C; delete D; } 107 | var_decl(A) ::= type(B) var_no_assign(C) var_list_no_assign(D) custom_var_decl(E) SEMICOLON. { C->type = B; C->custom_vars = *E; C->names = *D; A = C; delete D; delete E; } 108 | var_decl(A) ::= id(B) var_no_assign(C) var_list_no_assign(D) custom_var_decl(E) SEMICOLON. { C->type = new NType(B); C->names = *D; C->custom_vars = *E; A = C; delete D; delete E; } 109 | 110 | var(A) ::= id(B) array(C). { A = new NVariable(B, C); } 111 | var(A) ::= id(B) array(C) ASSIGN op_if(D). { A = new NVariable(B, C); A->value = D; } 112 | 113 | var_no_assign(A) ::= id(B) array(C). { A = new NVariable(B, C); } 114 | var_no_assign(A) ::= id(B) COLON number(C). { A = new NVariable(B, NULL, C); } 115 | var_no_assign(A) ::= id(B) O_ROUND expr(C) C_ROUND. { A = new NVariable(B, NULL); A->constructor = *C; delete C; } 116 | var_no_assign(A) ::= COLON number(C). { A = new NVariable(C); } 117 | 118 | array(A) ::= O_SQUARE expr(B) C_SQUARE. { A = new NBlock(*B); delete B; } 119 | array(A) ::= O_SQUARE C_SQUARE. { A = new NBlock(); } 120 | array(A) ::= . { A = NULL; } 121 | 122 | var_list(A) ::= var_list COMMA var(B). { A->push_back(B); } 123 | var_list(A) ::= COMMA var(B). { A = new NodeList(); A->push_back(B); } 124 | var_list(A) ::= . { A = new NodeList(); } 125 | 126 | var_list_no_assign(A) ::= var_list_no_assign COMMA var_no_assign(B). { A->push_back(B); } 127 | var_list_no_assign(A) ::= COMMA var_no_assign(B). { A = new NodeList(); A->push_back(B); } 128 | var_list_no_assign(A) ::= . { A = new NodeList(); } 129 | 130 | // ======================================================= 131 | // Enumerations 132 | // ======================================================= 133 | 134 | enum_def(A) ::= enum_def COMMA enum_val(B). { A->push_back(B); } 135 | enum_def(A) ::= enum_val(B). { A = new NodeList(); A->push_back(B); } 136 | 137 | enum_val(A) ::= id(B) ASSIGN number(C). { A = new NEnumValue(B, C); } 138 | enum_val(A) ::= id(B). { A = new NEnumValue(B); } 139 | 140 | enum_type(A) ::= LT type(B) GT. { A = B; } 141 | enum_type(A) ::= . { A = NULL; } 142 | 143 | // ======================================================= 144 | // Types 145 | // ======================================================= 146 | 147 | custom_vars(A) ::= custom_vars COMMA custom_var(B). { A->push_back(B); } 148 | custom_vars(A) ::= custom_var(B). { A = new NodeList(); A->push_back(B); } 149 | 150 | custom_var(A) ::= IDENTIFIER(B) ASSIGN id(C). { A = new NCustomVariable(B->value, C); } 151 | custom_var(A) ::= IDENTIFIER(B) ASSIGN literal(C). { A = new NCustomVariable(B->value, C); } 152 | 153 | type(A) ::= sign(B) scalar(C). { if(B != -1) C->is_signed = B; A = C; } 154 | type(A) ::= sign character(B). { A = B; } 155 | type(A) ::= string(B). { A = B; } 156 | type(A) ::= datetime(B). { A = B; } 157 | type(A) ::= STRUCT id(B) args_decl(C) O_CURLY struct_stms(D) C_CURLY. { A = new NStruct(B, *C, *D); delete C; delete D; } 158 | type(A) ::= UNION id(B) args_decl(C) O_CURLY struct_stms(D) C_CURLY. { A = new NUnion(B, *C, *D); delete C; delete D; } 159 | type(A) ::= ENUM enum_type(B) id(C) O_CURLY enum_def(D) C_CURLY. { A = new NEnum(C, *D, B); delete D; } 160 | type(A) ::= ENUM enum_type(B) O_CURLY enum_def(C) C_CURLY. { A = new NEnum(*C, B); delete C; } 161 | type(A) ::= ENUM type(B) O_CURLY enum_def(C) C_CURLY. { A = new NEnum(*C, B); delete C; } 162 | type(A) ::= STRUCT args_decl(B) O_CURLY struct_stms(C) C_CURLY. { A = new NStruct(*B, *C); delete B; delete C; } 163 | type(A) ::= UNION args_decl(B) O_CURLY struct_stms(C) C_CURLY. { A = new NUnion(*B, *C); delete B; delete C; } 164 | type(A) ::= VOID(B). { A = new NType(B->value); } 165 | type(A) ::= BOOL(B). { A = new NBooleanType(B->value); } 166 | 167 | sign(A) ::= UNSIGNED. { A = 0; } 168 | sign(A) ::= SIGNED. { A = 1; } 169 | sign(A) ::= . { A = -1; } 170 | 171 | string(A) ::= WSTRING(B). { A = new NStringType(B->value); } 172 | string(A) ::= STRING(B). { A = new NStringType(B->value); } 173 | string(A) ::= character(B). { A = B; } 174 | 175 | character(A) ::= CHAR(B). { A = new NCharType(B->value); } 176 | character(A) ::= WCHAR(B). { A = new NCharType(B->value); } 177 | character(A) ::= BYTE(B). { A = new NCharType(B->value); } 178 | 179 | datetime(A) ::= TIME(B). { A = new NTime(B->value); } 180 | datetime(A) ::= DOSDATE(B). { A = new NDosDate(B->value); } 181 | datetime(A) ::= DOSTIME(B). { A = new NDosTime(B->value); } 182 | datetime(A) ::= OLETIME(B). { A = new NOleTime(B->value); } 183 | datetime(A) ::= FILETIME(B). { A = new NFileTime(B->value); } 184 | 185 | scalar(A) ::= UCHAR(B). { A = new NScalarType(B->value, 8); A->is_signed = false; } 186 | scalar(A) ::= UBYTE(B). { A = new NScalarType(B->value, 8); A->is_signed = false; } 187 | scalar(A) ::= SHORT(B). { A = new NScalarType(B->value, 16); } 188 | scalar(A) ::= USHORT(B). { A = new NScalarType(B->value, 16); A->is_signed = false; } 189 | scalar(A) ::= INT32(B). { A = new NScalarType(B->value, 32); } 190 | scalar(A) ::= UINT32(B). { A = new NScalarType(B->value, 32); A->is_signed = false; } 191 | scalar(A) ::= INT64(B). { A = new NScalarType(B->value, 64); } 192 | scalar(A) ::= UINT64(B). { A = new NScalarType(B->value, 64); A->is_signed = false; } 193 | scalar(A) ::= HFLOAT(B). { A = new NScalarType(B->value, 16); A->is_fp = true; } 194 | scalar(A) ::= FLOAT(B). { A = new NScalarType(B->value, 32); A->is_fp = true; } 195 | scalar(A) ::= DOUBLE(B). { A = new NScalarType(B->value, 64); A->is_fp = true; } 196 | 197 | // ======================================================= 198 | // Statements 199 | // ======================================================= 200 | 201 | struct_stms(A) ::= struct_stms stm(B). { A->push_back(B); } 202 | struct_stms(A) ::= stm(B). { A = new NodeList(); A->push_back(B); } 203 | struct_stms(A) ::= . { A = new NodeList(); } 204 | 205 | stm(A) ::= IF O_ROUND expr(B) C_ROUND stm(C). { A = new NConditional(new NBlock(*B), C); delete B; } 206 | stm(A) ::= IF O_ROUND expr(B) C_ROUND then_stm(C) ELSE stm(D). { A = new NConditional(new NBlock(*B), C, D); delete B; } 207 | stm(A) ::= WHILE O_ROUND expr(B) C_ROUND stm(C). { A = new NWhile(new NBlock(*B), C); delete B; } 208 | stm(A) ::= FOR O_ROUND arg(B) SEMICOLON arg(C) SEMICOLON arg(D) C_ROUND stm(E). { A = new NFor(B, C, D, E); } 209 | stm(A) ::= normal_stm(B). { A = B; } 210 | 211 | then_stm(A) ::= IF O_ROUND expr(B) C_ROUND then_stm(C) ELSE then_stm(D). { A = new NConditional(new NBlock(*B), C, D); delete B; } 212 | then_stm(A) ::= WHILE O_ROUND expr(B) C_ROUND then_stm(C). { A = new NWhile(new NBlock(*B), C); delete B; } 213 | then_stm(A) ::= FOR O_ROUND arg(B) SEMICOLON arg(C) SEMICOLON arg(D) C_ROUND then_stm(E). { A = new NFor(B, C, D, E); } 214 | then_stm(A) ::= normal_stm(B). { A = B; } 215 | 216 | normal_stm(A) ::= DO stm(B) WHILE O_ROUND expr(C) C_ROUND SEMICOLON. { A = new NDoWhile(B, new NBlock(*C)); delete C; } 217 | normal_stm(A) ::= SWITCH O_ROUND expr(B) C_ROUND O_CURLY case_stms(C) C_CURLY. { A = new NSwitch(new NBlock(*B), *C); delete B, delete C; } 218 | normal_stm(A) ::= var_decl(B). { A = B; } 219 | normal_stm(A) ::= block(B). { A = B; } 220 | normal_stm(A) ::= return_stm(B). { A = B; } 221 | normal_stm(A) ::= expr(B) SEMICOLON. { A = new NBlock(*B); delete B; } 222 | normal_stm(A) ::= BREAK SEMICOLON. { A = new NVMState(VMState::Break); } 223 | normal_stm(A) ::= CONTINUE SEMICOLON. { A = new NVMState(VMState::Continue); } 224 | normal_stm(A) ::= SEMICOLON. { A = new NBlock(); } 225 | 226 | return_stm(A) ::= RETURN expr(B) SEMICOLON. { A = new NReturn(new NBlock(*B)); delete B; } 227 | return_stm(A) ::= RETURN SEMICOLON. { A = new NReturn(new NBlock()); } 228 | 229 | arg(A) ::= expr(B). { A = new NBlock(*B); delete B; } 230 | arg(A) ::= . { A = new NBlock(); } 231 | 232 | case_stms(A) ::= case_stms case_stm(B). { A->push_back(B); } 233 | case_stms(A) ::= case_stm(B). { A = new NodeList(); A->push_back(B); } 234 | case_stms(A) ::= . { A = new NodeList(); } 235 | 236 | case_stm(A) ::= CASE value(B) COLON stm_list(C). { A = new NCase(B, new NBlock(*C)); delete C; } 237 | case_stm(A) ::= DEFAULT COLON stm_list(B). { A = new NCase(new NBlock(*B)); delete B; } 238 | 239 | block(A) ::= O_CURLY stm_list(B) C_CURLY. { A = new NBlock(*B); delete B; } 240 | 241 | stm_list(A) ::= stm_list stm(B). { A->push_back(B); } 242 | stm_list(A) ::= stm(B). { A = new NodeList(); A->push_back(B); } 243 | stm_list(A) ::= . { A = new NodeList(); } 244 | 245 | // ======================================================= 246 | // C's 15 level of operator precedence 247 | // ======================================================= 248 | 249 | expr(A) ::= expr COMMA op_assign(B). { A->push_back(B); } 250 | expr(A) ::= op_assign(B). { A = new NodeList(); A->push_back(B); } 251 | 252 | op_assign(A) ::= op_if(B) ASSIGN(C) op_assign(D). { A = new NBinaryOperator(B, C->value, D); } 253 | op_assign(A) ::= op_if(B) ADD_ASSIGN(C) op_assign(D). { A = new NBinaryOperator(B, C->value, D); } 254 | op_assign(A) ::= op_if(B) SUB_ASSIGN(C) op_assign(D). { A = new NBinaryOperator(B, C->value, D); } 255 | op_assign(A) ::= op_if(B) MUL_ASSIGN(C) op_assign(D). { A = new NBinaryOperator(B, C->value, D); } 256 | op_assign(A) ::= op_if(B) DIV_ASSIGN(C) op_assign(D). { A = new NBinaryOperator(B, C->value, D); } 257 | op_assign(A) ::= op_if(B) XOR_ASSIGN(C) op_assign(D). { A = new NBinaryOperator(B, C->value, D); } 258 | op_assign(A) ::= op_if(B) AND_ASSIGN(C) op_assign(D). { A = new NBinaryOperator(B, C->value, D); } 259 | op_assign(A) ::= op_if(B) OR_ASSIGN(C) op_assign(D). { A = new NBinaryOperator(B, C->value, D); } 260 | op_assign(A) ::= op_if(B) LS_ASSIGN(C) op_assign(D). { A = new NBinaryOperator(B, C->value, D); } 261 | op_assign(A) ::= op_if(B) RS_ASSIGN(C) op_assign(D). { A = new NBinaryOperator(B, C->value, D); } 262 | op_assign(A) ::= op_if(B). { A = B; } 263 | 264 | op_if(A) ::= op_or(B) QUESTION op_if(C) COLON op_if(D). { A = new NConditional(B, C, D); } 265 | op_if(A) ::= op_or(B). { A = B; } 266 | 267 | op_or(A) ::= op_or(B) LOG_OR(C) op_and(D). { A = new NBinaryOperator(B, C->value, D); } 268 | op_or(A) ::= op_and(B). { A = B; } 269 | 270 | op_and(A) ::= op_and(B) LOG_AND(C) op_binor(D). { A = new NBinaryOperator(B, C->value, D); } 271 | op_and(A) ::= op_binor(B). { A = B; } 272 | 273 | op_binor(A) ::= op_binor(B) BIN_OR(C) op_binxor(D). { A = new NBinaryOperator(B, C->value, D); } 274 | op_binor(A) ::= op_binxor(B). { A = B; } 275 | 276 | op_binxor(A) ::= op_binxor(B) BIN_XOR(C) op_binand(D). { A = new NBinaryOperator(B, C->value, D); } 277 | op_binxor(A) ::= op_binand(B). { A = B; } 278 | 279 | op_binand(A) ::= op_binand(B) BIN_AND(C) op_equate(D). { A = new NBinaryOperator(B, C->value, D); } 280 | op_binand(A) ::= op_equate(B). { A = B; } 281 | 282 | op_equate(A) ::= op_equate(B) EQ(C) op_compare(D). { A = new NCompareOperator(B, D, C->value); } 283 | op_equate(A) ::= op_equate(B) NE(C) op_compare(D). { A = new NCompareOperator(B, D, C->value); } 284 | op_equate(A) ::= op_compare(B). { A = B; } 285 | 286 | op_compare(A) ::= op_compare(B) LT(C) op_shift(D). { A = new NCompareOperator(B, D, C->value); } 287 | op_compare(A) ::= op_compare(B) GT(C) op_shift(D). { A = new NCompareOperator(B, D, C->value); } 288 | op_compare(A) ::= op_compare(B) LE(C) op_shift(D). { A = new NCompareOperator(B, D, C->value); } 289 | op_compare(A) ::= op_compare(B) GE(C) op_shift(D). { A = new NCompareOperator(B, D, C->value); } 290 | op_compare(A) ::= op_shift(B). { A = B; } 291 | 292 | op_shift(A) ::= op_shift(B) LSL(C) op_add(D). { A = new NBinaryOperator(B, C->value, D); } 293 | op_shift(A) ::= op_shift(B) LSR(C) op_add(D). { A = new NBinaryOperator(B, C->value, D); } 294 | op_shift(A) ::= op_add(B). { A = B; } 295 | 296 | op_add(A) ::= op_add(B) ADD(C) op_mult(D). { A = new NBinaryOperator(B, C->value, D); } 297 | op_add(A) ::= op_add(B) SUB(C) op_mult(D). { A = new NBinaryOperator(B, C->value, D); } 298 | op_add(A) ::= op_mult(B). { A = B; } 299 | 300 | op_mult(A) ::= op_mult(B) MUL(C) op_unary(D). { A = new NBinaryOperator(B, C->value, D); } 301 | op_mult(A) ::= op_mult(B) DIV(C) op_unary(D). { A = new NBinaryOperator(B, C->value, D); } 302 | op_mult(A) ::= op_mult(B) MOD(C) op_unary(D). { A = new NBinaryOperator(B, C->value, D); } 303 | op_mult(A) ::= op_unary(B). { A = B; } 304 | 305 | op_unary(A) ::= LOG_NOT(B) op_unary(C). { A = new NUnaryOperator(B->value, C, true); } 306 | op_unary(A) ::= BIN_NOT(B) op_unary(C). { A = new NUnaryOperator(B->value, C, true); } 307 | op_unary(A) ::= SUB(B) op_unary(C). { A = new NUnaryOperator(B->value, C, true); } 308 | op_unary(A) ::= INC(B) op_unary(C). { A = new NUnaryOperator(B->value, C, true); } 309 | op_unary(A) ::= DEC(B) op_unary(C). { A = new NUnaryOperator(B->value, C, true); } 310 | op_unary(A) ::= op_unary(B) INC(C). { A = new NUnaryOperator(C->value, B, false); } 311 | op_unary(A) ::= op_unary(B) DEC(C). { A = new NUnaryOperator(C->value, B, false); } 312 | op_unary(A) ::= O_ROUND type(B) C_ROUND op_unary(C). { A = new NCast(B, C); } 313 | op_unary(A) ::= SIZEOF O_ROUND type(B) C_ROUND. { A = new NSizeOf(B); } 314 | op_unary(A) ::= SIZEOF O_ROUND op_assign(B) C_ROUND. { A = new NSizeOf(B); } 315 | op_unary(A) ::= op_pointer(B). { A = B; } 316 | 317 | op_pointer(A) ::= op_pointer(B) DOT id(C). { A = new NDotOperator(B, C); } 318 | op_pointer(A) ::= op_pointer(B) O_SQUARE expr(C) C_SQUARE. { A = new NIndexOperator(B, new NBlock(*C)); delete C; } 319 | op_pointer(A) ::= value(B). { A = B; } 320 | 321 | // ======================================================= 322 | // Basic Declarations 323 | // ======================================================= 324 | 325 | value(A) ::= O_ROUND expr(B) C_ROUND. { A = new NBlock(*B); delete B; } 326 | value(A) ::= id(B) O_ROUND expr(C) C_ROUND. { A = new NCall(B, *C); delete C; } 327 | value(A) ::= id(B) O_ROUND C_ROUND. { A = new NCall(B); } 328 | value(A) ::= id(B). { A = B; } 329 | value(A) ::= literal(B). { A = B; } 330 | 331 | literal(A) ::= LITERAL_STRING(B). { A = new NString(B->value); } 332 | literal(A) ::= boolean(B). { A = B; } 333 | literal(A) ::= number(B). { A = B; } 334 | 335 | number(A) ::= LITERAL_CHAR(B). { A = new NInteger(VMFunctions::string_to_number(B->value, 8)); } 336 | number(A) ::= LITERAL_OCT(B). { A = new NInteger(VMFunctions::string_to_number(B->value, 8)); } 337 | number(A) ::= LITERAL_DEC(B). { A = new NInteger(VMFunctions::string_to_number(B->value, 10)); } 338 | number(A) ::= LITERAL_HEX(B). { A = new NInteger(VMFunctions::string_to_number(B->value, 16)); } 339 | number(A) ::= LITERAL_REAL(B). { A = new NReal(VMFunctions::string_to_number(B->value)); } 340 | 341 | boolean(A) ::= TRUE. { A = new NBoolean(true); } 342 | boolean(A) ::= FALSE. { A = new NBoolean(false); } 343 | 344 | id(A) ::= IDENTIFIER(B). { A = new NIdentifier(B->value); } 345 | -------------------------------------------------------------------------------- /tests/BTVMTest.bt: -------------------------------------------------------------------------------- 1 | // -------------------------------------- 2 | // HELPER FUNCTIONS 3 | // -------------------------------------- 4 | 5 | enum { ZERO_A, ONE_A, TWO_A, THREE_A, TEN_A = 10, ELEVEN_A }; 6 | enum UntypedEnum { ZERO, ONE, TWO, THREE, TEN = 10, ELEVEN }; 7 | enum TypedEnum { ZERO_T, ONE_T, TWO_T, THREE_T, TEN_T = 10, ELEVEN_T }; 8 | 9 | int sum(int a, int b) { return a + b; } 10 | int pow(int val) { return val * val; } 11 | 12 | void by_value(int val) { val++; } 13 | void by_reference(int& val) { val++; } 14 | 15 | int return_function(int a) { return (a >= 100 ? a * 100 : -a); } 16 | 17 | int return_loop_conditional(int val) 18 | { 19 | local int i=0; 20 | 21 | for(i=0; i < 10; i++) 22 | { 23 | if((i >= 5) && (i <= 10)) 24 | { 25 | if((val >= 5) && (val <= 10)) 26 | return val * 10; 27 | } 28 | } 29 | 30 | return 0; 31 | } 32 | 33 | // -------------------------------------- 34 | // TEST CASES 35 | // -------------------------------------- 36 | void test_basic_sizeof() 37 | { 38 | Printf("8-Bit signed integer sizes..."); 39 | __btvm_test__((sizeof(char) == 1) && (sizeof(byte) == 1) && (sizeof(CHAR) == 1) && (sizeof(BYTE) == 1)); 40 | 41 | Printf("8-Bit unsigned integer sizes..."); 42 | __btvm_test__((sizeof(uchar) == 1) && (sizeof(ubyte) == 1) && (sizeof(UCHAR) == 1) && (sizeof(UBYTE) == 1)); 43 | 44 | Printf("16-Bit signed integer sizes..."); 45 | __btvm_test__((sizeof(short) == 2) && (sizeof(int16) == 2) && (sizeof(SHORT) == 2) && (sizeof(INT16) == 2)); 46 | 47 | Printf("16-Bit unsigned integer sizes..."); 48 | __btvm_test__((sizeof(ushort) == 2) && (sizeof(uint16) == 2) && (sizeof(USHORT) == 2) && (sizeof(UINT16) == 2) && sizeof(WORD) = 2); 49 | 50 | Printf("32-Bit signed integer sizes..."); 51 | __btvm_test__((sizeof(int) == 4) && (sizeof(int32) == 4) && (sizeof(long) == 4) && (sizeof(INT) == 4) && (sizeof(INT32) == 4) && (sizeof(LONG) == 4)); 52 | 53 | Printf("32-Bit unsigned integer sizes..."); 54 | __btvm_test__((sizeof(uint) == 4) && (sizeof(uint32) == 4) && (sizeof(ulong) == 4) && (sizeof(UINT) == 4) && (sizeof(UINT32) == 4) && (sizeof(ULONG) == 4) && (sizeof(DWORD) == 4)); 55 | 56 | Printf("64-Bit signed integer sizes..."); 57 | __btvm_test__((sizeof(int64) == 8) && (sizeof(quad) == 8) && (sizeof(QUAD) == 8) && (sizeof(INT64) == 8) && (sizeof(__int64) == 8)); 58 | 59 | Printf("64-Bit unsigned integer sizes..."); 60 | __btvm_test__((sizeof(uint64) == 8) && (sizeof(uquad) == 8) && (sizeof(UQUAD) == 8) && (sizeof(UINT64) == 8) && (sizeof(QWORD) == 8) && (sizeof(__uint64) == 8)); 61 | 62 | Printf("16-Bit floating point sizes..."); 63 | __btvm_test__((sizeof(hfloat) == 2) && (sizeof(HFLOAT) == 2)); 64 | 65 | Printf("32-Bit floating point sizes..."); 66 | __btvm_test__((sizeof(float) == 4) && (sizeof(FLOAT) == 4)); 67 | 68 | Printf("64-Bit floating point sizes..."); 69 | __btvm_test__((sizeof(double) == 8) && (sizeof(DOUBLE) == 8)); 70 | } 71 | 72 | void test_multivars() 73 | { 74 | Printf("Multiple variables..."); 75 | 76 | local int f = 10, g = 15, h = 20; 77 | __btvm_test__((f == 10) && (g == 15) && (h == 20)); 78 | } 79 | 80 | void test_array() 81 | { 82 | Printf("Array types..."); 83 | 84 | local int a[3]; 85 | a[0] = 123; 86 | a[1] = 456; 87 | a[2] = 789; 88 | 89 | __btvm_test__((a[0] == 123) && (a[1] == 456) && (a[2] == 789)); 90 | 91 | Printf("Array math..."); 92 | a[0] += 666; 93 | a[2] -= 666; 94 | 95 | __btvm_test__((a[2] == 123) && (a[1] == 456) && (a[0] == 789)); 96 | } 97 | 98 | void test_untyped_enum() 99 | { 100 | Printf("Untyped enum values..."); 101 | 102 | local UntypedEnum utenum; 103 | 104 | __btvm_test__((utenum.ZERO == 0) && 105 | (utenum.ONE == 1) && 106 | (utenum.TWO == 2) && 107 | (utenum.THREE == 3) && 108 | (utenum.TEN == 10) && 109 | (utenum.ELEVEN == 11)); 110 | 111 | Printf("Untyped enum size [type]..."); 112 | __btvm_test__(sizeof(UntypedEnum) == 4); 113 | 114 | Printf("Untyped enum size [variable]..."); 115 | __btvm_test__(sizeof(utenum) == 4); 116 | } 117 | 118 | void test_typed_enum() 119 | { 120 | Printf("Typed enum values..."); 121 | 122 | local TypedEnum tenum; 123 | 124 | __btvm_test__((tenum.ZERO_T == 0) && 125 | (tenum.ONE_T == 1) && 126 | (tenum.TWO_T == 2) && 127 | (tenum.THREE_T == 3) && 128 | (tenum.TEN_T == 10) && 129 | (tenum.ELEVEN_T == 11)); 130 | 131 | Printf("Typed enum size [type]..."); 132 | __btvm_test__(sizeof(TypedEnum) == 2); 133 | 134 | Printf("Typed enum size [variable]..."); 135 | __btvm_test__(sizeof(tenum) == 2); 136 | } 137 | 138 | void test_anonymous_enum() 139 | { 140 | Printf("Anonymous enum values..."); 141 | 142 | __btvm_test__((ZERO_A == 0) && 143 | (ONE_A == 1) && 144 | (TWO_A == 2) && 145 | (THREE_A == 3) && 146 | (TEN_A == 10) && 147 | (ELEVEN_A == 11)); 148 | } 149 | 150 | void test_math_expressions() 151 | { 152 | Printf("Add expression..."); 153 | __btvm_test__((95 + 5) == 100); 154 | 155 | Printf("Sub expression..."); 156 | __btvm_test__((95 - 5) == 90); 157 | 158 | Printf("Mul expression..."); 159 | __btvm_test__((25 * 5) == 125); 160 | 161 | Printf("Div expression..."); 162 | __btvm_test__((125 / 5) == 25); 163 | 164 | Printf("Mod expression..."); 165 | __btvm_test__((25 % 7) == 4); 166 | 167 | Printf("Composite expression..."); 168 | __btvm_test__(((100 * 10) - (250 * 2)) == 500); 169 | 170 | Printf("~ operator..."); 171 | __btvm_test__((~0xAAAAAAAA) == 0x55555555); 172 | 173 | Printf("<< operator..."); 174 | __btvm_test__((0x00000001 << 8) == 0x100); 175 | 176 | Printf(">> operator..."); 177 | __btvm_test__((0x00000100 >> 8) == 0x1); 178 | 179 | local int a = 255; 180 | 181 | Printf("Prefix ++ operator..."); 182 | __btvm_test__(++a == 256); 183 | 184 | Printf("Post-prefix ++ operator..."); 185 | __btvm_test__(a == 256); 186 | 187 | Printf("Postfix ++ operator..."); 188 | __btvm_test__(a++ == 256); 189 | 190 | Printf("Post-postfix ++ operator..."); 191 | __btvm_test__(a == 257); 192 | } 193 | 194 | void test_loop() 195 | { 196 | local int res = 0; 197 | 198 | Printf("For loop..."); 199 | 200 | local int i; 201 | 202 | for(i = 0; i < 10; i++) 203 | res++; 204 | 205 | __btvm_test__(res == 10); 206 | res = 0; 207 | 208 | Printf("Counter reset..."); 209 | __btvm_test__(!res); 210 | 211 | Printf("Do-While loop..."); 212 | 213 | do 214 | res++; 215 | while(res < 10); 216 | 217 | __btvm_test__(res == 10); 218 | res = 0; 219 | 220 | Printf("Counter reset..."); 221 | __btvm_test__(!res); 222 | 223 | Printf("While loop..."); 224 | 225 | while(res < 10) 226 | res++; 227 | 228 | __btvm_test__(res == 10); 229 | res = 0; 230 | 231 | Printf("Counter reset..."); 232 | __btvm_test__(!res); 233 | } 234 | 235 | void test_conditional() 236 | { 237 | local bool itrue = true, ifalse = false; 238 | 239 | Printf("Ternary operator [true]..."); 240 | itrue ? __btvm_test__(true) : __btvm_test__(false); 241 | 242 | Printf("Ternary operator [false]..."); 243 | ifalse ? __btvm_test__(false) : __btvm_test__(true); 244 | 245 | Printf("If-else statement [true]..."); 246 | 247 | if(itrue) 248 | __btvm_test__(true); 249 | else 250 | __btvm_test__(false); 251 | 252 | Printf("If-else statement [false]..."); 253 | 254 | if(!ifalse) 255 | __btvm_test__(true); 256 | else 257 | __btvm_test__(false); 258 | } 259 | 260 | void test_switch() 261 | { 262 | local int i = 10; 263 | 264 | Printf("Switch statement [standard]..."); 265 | 266 | switch(i) 267 | { 268 | case 10: 269 | __btvm_test__(true); 270 | break; 271 | 272 | case 9: 273 | case 11: 274 | default: 275 | __btvm_test__(false); 276 | break; 277 | } 278 | 279 | Printf("Switch statement [fall-through]..."); 280 | 281 | switch(i) 282 | { 283 | case 10: 284 | i++; 285 | 286 | case 11: 287 | i--; 288 | __btvm_test__(i == 10); 289 | break; 290 | 291 | case 9: 292 | default: 293 | __btvm_test__(false); 294 | break; 295 | } 296 | 297 | Printf("Switch statement [default-case]..."); 298 | 299 | i = 50; 300 | 301 | switch(i) 302 | { 303 | case 9: 304 | case 10: 305 | case 11: 306 | __btvm_test__(false); 307 | break; 308 | 309 | default: 310 | __btvm_test__(true); 311 | break; 312 | } 313 | } 314 | 315 | void test_conditional_return() 316 | { 317 | local int i = 150; 318 | 319 | Printf("Conditional Return statement [case 1]..."); 320 | __btvm_test__(return_function(i) == (i * 100)); 321 | 322 | i = 80; 323 | 324 | Printf("Conditional Return statement [case 2]..."); 325 | __btvm_test__(return_function(i) == -i); 326 | 327 | Printf("Conditional Return Loop statement [case 1]..."); 328 | __btvm_test__(return_loop_conditional(10) == 100); 329 | 330 | Printf("Conditional Return Loop statement [case 2]..."); 331 | __btvm_test__(return_loop_conditional(1) == 0); 332 | } 333 | 334 | void test_function_call() 335 | { 336 | Printf("Sum call..."); 337 | __btvm_test__(sum(50, 30) == 80); 338 | 339 | Printf("Pow call..."); 340 | __btvm_test__(pow(10) == 100); 341 | } 342 | 343 | void test_by_reference() 344 | { 345 | local int val = 10; 346 | 347 | Printf("By value parameter..."); 348 | by_value(val); 349 | __btvm_test__(val == 10); 350 | 351 | Printf("By reference parameter..."); 352 | by_reference(val); 353 | __btvm_test__(val == 11); 354 | } 355 | 356 | Printf("*** *** Starting tests *** ***\n"); 357 | 358 | test_basic_sizeof(); 359 | test_multivars(); 360 | test_array(); 361 | test_untyped_enum(); 362 | test_typed_enum(); 363 | test_anonymous_enum(); 364 | test_math_expressions(); 365 | test_loop(); 366 | test_conditional(); 367 | test_conditional_return(); 368 | test_switch(); 369 | test_function_call(); 370 | test_by_reference(); 371 | 372 | Printf("*** *** Ending tests *** ***\n"); 373 | --------------------------------------------------------------------------------