├── 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) ("" + 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